Это анти-шаблон или нарушает какие-то принципы дизайна? - PullRequest
0 голосов
/ 09 мая 2018

Я пробую себя с шаблонами и принципами дизайна и у меня есть вопрос. Раньше извините за плохую привычку в стиле кодирования !!

В этом случае у меня есть интерфейс, подобный ITest:

public interface ITest
{
    public void method1();
}

и затем внедрить методы и поля, если таковые имеются, в конкретный класс B следующим образом:

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");
    }
}

Теперь в коде приложения я вставил его так:

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
    }
}

Вы видите, что method2 () из класса B недоступен из-за интерфейса ITest. Теперь, что если мне нужен этот «важный» метод? Есть несколько возможностей. Я мог бы абстрагировать его в интерфейсе, или сделать класс B абстрактным, и расширить его до другого класса и т. Д., Или сделать ссылку в методе main (), например:

B test = new B();

Но это нарушило бы принцип. Итак, я изменил интерфейс:

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

И поместить в класс B реализацию:

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");
    }
}

Теперь в моем методе main () я могу вызывать оба метода с небольшим механизмом хука или цепочки, не ссылаясь на новый объект, и при этом он не нарушает принцип дизайна, и мне не нужен дополнительный класс для расширения или абстракции.

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()));
    }
}

Кроме того, я могу инкапсулировать, наследовать и абстрагировать другие методы, поля и т. Д. Это означает, что я могу создавать более сложные и гибкие иерархии.

Мой вопрос сейчас: Это своего рода анти-шаблон, плохой принцип дизайна или мы можем извлечь из этого выгоду?

Спасибо за просмотр. : -)

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Это что-то вроде анти-паттерна, плохого принципа дизайна или мы могли бы выиграть от этого?

Да, это плохая картина.

Проблема связана с тем, что вы тесно связали ITest с B. Скажем, я хочу создать новую реализацию ITest - назовем ее C.

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

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

Нет разумного способа, которым мы можем реализовать этот метод. Единственное разумное, что нужно сделать, это вернуть null. Это заставит любых пользователей нашего интерфейса постоянно выполнять защитные нулевые проверки.

Если им придется каждый раз проверять, прежде чем использовать результат метода, они могут просто выполнить instanceof и привести к B. Так какую ценность вы добавляете? Вы просто делаете интерфейс менее понятным и более запутанным.

0 голосов
/ 09 мая 2018

Добавление метода, возвращающего B к интерфейсу ITest, реализованного с помощью B, безусловно, ужасный выбор дизайна, потому что он заставляет другие классы, реализующие ITest return B, например

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

Ваш первый выбор лучше:

B test1 = new B();
C test2 = new C();
...