Interface initialization anti-patterns

Spread the love

It’s a pain that you cannot define constructors for interfaces, isn’t it? To be honest, I’m not so sure… The perceived need for a constructor — typically realized as an Init()-style method — is often a sign of a design issue.

Let’s say that you need to report performance metrics for a transaction processing component. However, before you send the first data point, you need to initialize some information such as the component instance name. You might define an interface like so:

interface IMetrics
{
    void Init(string instanceName);

    void ReportLatency(string operation, TimeSpan latency);

    void ReportDataRead(string operation, long bytesRead);
}

There are many potential pitfalls here. First, initialization is something that happens only initially, but the interface does not have any way of directly enforcing this. You could easily call Init() zero times, or twice, or a thousand times without noticing there is a problem until runtime (maybe? hopefully?). Second, and perhaps more relevant to this discussion, is the fact that initialization seems out of place on this interface. While it might be true that initialization is a necessary fact of life for this particular metrics pipeline, that sort of knowledge would likely be better off one layer above.

In some ways, this is just another form of the problem I subtly alluded to in a previous blog post. These pesky parameters (in this case, initialization parameters) should have been dealt with at the time the object was constructed. This makes the calling code much simpler and more straightforward — just report! Initialization, after all, is often an implementation detail.

But what if you really need to provide specific initialization data to an object, and the data is not readily available upfront? In that case, you probably want a factory. Given the above example, that might look something like this:

interface IMetricsFactory
{
    IMetrics Create(string instanceName);
}

Now you can pass an IMetricsFactory where you previously had plain old IMetrics and get a new instance anytime you need it.

Leave initialization to the professionals — entry points and factories. Let your interfaces be unencumbered with such details.

One thought on “Interface initialization anti-patterns

  1. Pingback: Interface anti-patterns: overload overload – WriteAsync .NET

Leave a Reply

Your email address will not be published. Required fields are marked *