Question

I am currently working on a network health monitoring system that allows to watch multiple kind of resources, diagnose based on facts and react according to the diagnostic.

Initial thoughs...

My initial thoughts was to have an abstract Watcher class, which can be configured with a Diagnosis object (which is responsible for producing a Diagnostic based on Facts) and a list of DiagnosticHandler objects. This Watcher class would have a abstract protected Facts _check() template method overridden by subclasses such as HttpWatcher or MemoryWatcher.

Facts is a marker interface and represents what can be observed to generate a Diagnostic. For example, the _check method of HttpWatcher would return HttpFacts which is basically the http response details.

Here's what the HttpWatcher constructor may look like:

public HttpWatcher(
    Duration interval, 
    Diagnosis<HttpFacts> diagnosis, 
    List<DiagnosticHandler> handlers,
    URL url
)

As we can see, since this class's _check method returns HttpFacts, it also only allows Diagnosis strategies that can diagnose based on HttpFacts and that is what we want. This way it is possible for the compiler to complain if an incompatible Diagnosis strategy is used.

Missing concept?

However, there is something that bother's me with this design because I noticed that in terms of behavior, the only thing that Watcher subclasses overrides is the _check method. Even worse, the _check algorithm could not be reused somewhere else. This made me thinking that perhaps I was missing a Resource concept in my design that could encapsulate the algorithm to retrieve Facts rather than having to subclass Watcher.

This being said, I would only need a concrete Watcher class which would be configured with a Resource, a Diagnosis<T extends Facts> and a List<DiagnosticHandler>.

This design makes much more sense to me, but then I would lose the type-safety that prevents incompatible strategies to be used together like below:

new Watcher(
    new Duration(...),
    new HttpResource(...),
    new SimpleMemoryDiagnosis(...), /*<- incompatible with HttpResource*/
    ...
)

Solution?

It's been a while since I programmed in a strongly-typed language and I want to make sure that I use the types to my advantage, but at the same time I do not want my design to suffer.

One idea that I had was to create a new class such as HttpWatchedResource which would encapsulate HttpResource and Diagnosis<HttpFacts> objects.

Something like:

public abstract class WatchedResource {
    private final Resource resource;
    private final Diagnosis diagnosis;

    public WatchedResource(Resource resource, Diagnosis diagnosis) {
        //null checks
        this.resource = resource;
        this.diagnosis = diagnosis;
    }

    //called by Watcher
    public final Diagnostic checkHealth() {
        return diagnosis.diagnose(resource.facts());
    }
}

public final class HttpWatchedResource {
    public HttpWatchedResource(HttpResource resource, Diagnosis<HttpFacts> diagnosis) {
        super(resource, diagnosis);
    }
}

The Watcher constructor would then look like:

public Watcher(
    Duration interval, 
    WatchedResource resource, 
    List<DiagnosticHandler> handlers,
    URL url
)

I would like to know if there's a widely adopted pattern used when an object is composed of multiple strategies that could potentially be incompatible and/or if I'm heading in the right direction with the proposed solution?

Was it helpful?

Solution

I might be missing something, but based on my current understanding of the problem I would do something like:

public class Watcher<T> {
    public Watcher(Resource<T> res, Diagnosis<T> diag) {
    ...
    }
}

and

public class HttpResource implements Resource<HttpFacts> {
   ...
}

That would guarantee that the Watcher and the Diagnosis are always of compatible types, and still allow you to override either.

I might very well be missing something crucial though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top