Pergunta

I'm designing an architecture in which I have:

public interface IObjectReader{
    public Object read();
}

public class ConcreteObjectReader implements IObjectReader{
     @Override
     public Object read(){
         //do stuff
         return new Object();
     }
}

Now, if I want to allow a reader to be parameterized, I could create another interface this way:

public interface IParameterizedObjectReader extends IObjectReader {
    public void setParams(Map<String,String> params);
    public Map<String,String> getParams();
}

To me this is reasonable. However, in my project I have also object writers, object processors and so on, and they also need to be, eventually, parameterized. In this scenario, having two or more interfaces that define the same contract (getParams and setParams) is a very bad idea to me. So I would define an interface IParameter like this:

public interface IParameter{
    public void setParams(Map<String,String> params);
    public Map<String, String> getParams();
}

and I'd make the IParametereziedObjectReader interface (similar for IParameterizedObjectWriter, etc) extend IParameter too, but I'd leave it empty.

Is this a bad idea? Or maybe I should leave only the IParameter interface and delete its subinterfaces? For clarity I have to say that I don't use these Parameterized interfaces as markers anywhere in my code, so they'd be empty just for an architectural reason.

How would you design this solution differently?

Foi útil?

Solução

Are empty interfaces (but not marker interfaces) a bad programming practice?

Generally, yes. By definition, empty interfaces provide you nothing. They can be marker interfaces (generally evil), or aliases for another type (occasionally useful due to legacy code when renaming something). But in a greenfield project like this they're just over-engineering and YAGNI.

How would you design this solution differently?

Without knowing more about your requirements, I can't say. But trying to make arbitrary read/write/process, with arbitrary number/shape of parameters is a fool's errand. Systems that can "do anything" aren't providing any useful abstraction over just writing code, and tend to be nightmares to implement and maintain. If you want a scripting language, go use a scripting language.

Outras dicas

Building a tree of interfaces, having one interface inherit from another, will soon defeat the purpose of having interfaces in the first place. You might as well build a class tree and use no interfaces at all.

It is always better to have multiple small interfaces, each with a single feature, than to have one compound interface that does it all but serves a single scenario. With the latter you really tie the interface to a class you already have in the back of your head, making it useless for anything else, hence pointless to have.

So in your particular example you want an IReader and an IParameterizable interface that are independent of eachother, each defining a single feature rather than the full feature set of some arbitrary class.

This looks like a job for the Interface Segregation Principle!

You say you want to create this:

public interface IParameterizedObjectReader extends IObjectReader {
    public void setParams(Map<String,String> params);
    public Map<String,String> getParams();
}

Or this:

public interface IParameterizedObjectReader extends IObjectReader, IParameter { }

I ask, do you need this:

IParameter p;

and this:

IObjectReader oReader;

and this:

IParameterizedObjectReader por;

Because if you don't have clients that need them all, you're making things a bit difficult for a hard to see reason. The fact that an interface might be empty because it gets what it promises from the interfaces it extends really means nothing to me. I simply like the lack of duplication. But it doesn't justify or undermine the existence of the interface.

What justifies the existence of an interface is that some client wants to use it. Clients OWN the interfaces. They need the things the interface promises. Nothing cares if it was defined with an empty body. Hell, the interface might simply exist to provide name indirection.

And yes, you can create complexity this way. Don't create it because of "architectural reasons". Create it because something needs it. Now. Today.

Clients shouldn't have to know about methods they don't care about. Follow this rule an your interfaces will be role interfaces. Each will exist for a good reason. Will have a single responsibility. And not result in a combinatorial explosion of an interface for every possible set of methods.

Oh, and remember, the IMyInterface prefix is a C# thing. Java does the MyImplementationImpl suffix thing. Both are terrible things but those are the things.

The fact that reader, writer and processors have methods with common signature is just accidental circumstances.

Introducing IParameter interface will bound your reader, writer and processor abstractions under same contract signature.
After first change request where you need add one more argument to the reader class or change parameter type - you will throw your IParameter away.

Since your application need both parameterless and parameterized readers - consider introducing reader with two methods.

public interface IObjectReader
{
    public Object read();
    public Object read(Map<String,String> params);
}
Licenciado em: CC-BY-SA com atribuição
scroll top