3

I try myself with design-patterns & -principles and have a question. Before, sorry for the bad coding-style habit !!

I have an interface like ITest in this case:

public interface ITest
{
    public void method1();
}

and then implement the methods and fields, if any, into a concrete class B like this:

public class B implements ITest
{
    //This is the method from the interface
    @Override
    public void method1()
    {
        System.out.println("method1");
    }

    //This is another method in class B
    public void method2()
    {
        System.out.println("method2");
    }
}

Now in the application code I put it in like this:

public class Main 
{
    public static void main(final String args[]) throws Exception 
    {
        //One principle says:
        //programm to an interface instead to an implementation
        ITest test = new B();

        //method from interface
        test.method1();
        //this method is not accessible because not part of ITest
        test.method2();     //compile-time error
    }
}

You see that method2() from class B is not available because to the interface of ITest. Now, what if I need this 'important' method? There are several possibilities. I could abstract it in the interface or make class B abstract and extend into another class and so on, or make the reference in the main() method like:

B test = new B();

But this would violate the principle. So, I modified the interface to:

public interface ITest
{
    //A method to return the class-type B
    public B hook();
    public void method1();
}

And put in class B the implementation:

public class B implements ITest
{
    //this returns the object reference of itself
    @Override
    public B hook()
    {
        return this;
    }

    //This is the method from the interface
    @Override
    public void method1()
    {
        System.out.println("method1");
    }

    //This is the 'important' method in class B
    public void method2()
    {
        System.out.println("method2");
    }
}

Now in my main()-method I can call both methods with a little hook or chaining mechanism without referencing a new object nor does it violate the design-principle and I don't need an extra class for extension or abstraction.

public class Main
{
    public static void main(final String args[])
    {
        //programm to an interface instead into an implemintation
        ITest test = new B();
        //method from interface
        test.method1();
        //method2 will not be accessible from ITest so we referencing B through a method hook()
        //benefits: we don't need to create extra objects nor additional classes but only referencing
        test.hook().method2();
        System.out.println("Are they both equal: "+test.equals(test.hook()));
    }
}

Also, I can encapsulate, inherit and abstract other methods, fields etc. This means, that I can create more complex and flexible hierarchies.

My question now: Is this a kind of anti-pattern, bad design-principle or could we benefit from this?

Thank you for watching. :-)

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
PriNova
  • 33
  • 4

2 Answers2

3

Is this a kind of anti-pattern, bad design-principle or could we benefit from this?

Yes, it is a bad pattern.

The problem stems from the fact that you have tightly coupled ITest to B. Say I want to create a new implementation of ITest - let's call it C.

public class C implements ITest
{
    @Override
    public B hook()
    {
        // How do I implement this?
    }

    @Override
    public void method1()
    {
        System.out.println("method1");
    }
}

There's no sane way we can implement this method. The only reasonable thing to do is to return null. Doing so would force any users of our interface to constantly perform defensive null checks.

If they're going to have to check every time before using the result of the method, they might as well just do an instanceof and cast to B. So what value are you adding? You're just making the interface less coherent and more confusing.

Michael
  • 41,989
  • 11
  • 82
  • 128
2

Adding a method returning B to interface ITest implemented by B is definitely an awful design choice, because it forces other classes implementing ITest return B, for example

public class C implements ITest {
    @Override
    public B hook()
    {
        return // What do I return here? C is not a B
    }
    ...
}

Your first choice is better:

B test1 = new B();
C test2 = new C();
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523