Твердый образец регулятора GRASP?

У меня есть вопрос о применении шаблона контроллера GRASP, в то время как он остается твердым, а точнее, с единственной ответственностью.

Определение шаблона контроллера Википедии гласит:

Шаблон Controller назначает ответственность за обработку системных событий не-UI-классу, который представляет всю систему или сценарий варианта использования. Объект Controller - это объект не пользовательского интерфейса, отвечающий за получение или обработку системного события.

И о едином принципе ответственности SOLID:

В объектно-ориентированном программировании принцип единой ответственности гласит, что каждый класс должен нести одну ответственность, и эта ответственность должна быть полностью инкапсулирована классом. Все его услуги должны быть тесно связаны с этой ответственностью.

Давайте перейдем к примеру кода. Допустим, у меня есть следующие классы Java:

public class foo {
    public foo(){}
    public int foo1(){/*Some code*/}
    public String foo2(){/*Some code*/}
    public String foo3(int foo31){/*Some code*/}
}

public class bar {
    public bar(){}
    public int bar1(){/*Some code*/}
    public String bar2(){/*Some code*/}
    public String bar3(int bar31){/*Some code*/}
}

Какова хорошая реализация контроллера, сохраняя при этом одну ответственность за него? Я просто прохожу варианты использования или как? Например:

public class bazController {

    private foo fooInstance;
    private bar barInstance;

    public bazController(){
        this.fooInstance = new foo();
        this.barInstance = new bar();
    }

    public void fooAction1(int arg){
        this.foo.foo3(arg);
    }

    public void barAction1(int arg){
        this.bar.bar3(arg);
    }

    public void fooAction2(){
        this.foo.foo1();
    }

    public void barAction2(){
        this.bar.bar1();
    }

}

Я держу одну ответственность здесь? Я делаю это или правильно понимаю? Спасибо заранее.

РЕДАКТИРОВАТЬ: Что произойдет, если bazController имел этот метод, связывая оба класса?

public int bazAction(){
    return this.foo.fooAction1() + this.bar.barAction1();
}

2 ответа

Решение

Я не очень опытный разработчик, но я постараюсь изучить мои идеи по этому вопросу на основе понимания концепций.

Единственная ответственность: я полагаю, это ответ на вопрос "За что отвечает ваш класс?" когда вы собираетесь ответить на этот вопрос, вы должны сказать только одну ответственность. В вашем случае ответ таков: "Мой класс отвечает за управление базой"(ваша реализация, конечно, должна это делать).

Поскольку в вашем ответе указана только одна ответственность, вы правильно ее реализовали.

Но я думаю, что ваш код не соответствует D из SOLID, то есть внедрение зависимости. Вы могли бы ввести foo а также bar через конструктор или другими способами.

Обновление: Тем не менее, ваш класс в порядке, потому что ответственность вашего класса заключается в control the baz,

foo а также bar являются компонентами baz и вы контролируете их действие через ваш bazCntroller,

Я могу сказать, что вы нарушили Single Responsibility когда вы добавляете методы, которые выполняют другую работу, чем управление базой. Пример:

public void LogBazExecution() {}
public int GetBazExecutionCount() {}

Как видите, это не является обязанностью baz controller чтобы отследить, сколько раз срабатывал баз.

Причиной этого принципа является ease of maintenance, Если для каждого класса предусмотрена только одна ответственность, вам будет легко найти место сбоя в вашей системе и легко расширить его при необходимости, не внося много новых ошибок.

Это действительно зависит от контекста классов foo и bar и от того, насколько тесно они связаны между собой с бизнес-контекстом контроллера.

В вашем примере у вас есть методы, которые работают с foo и методы, которые работают с bar, но ноль методов, которые работают с обоими foo а также bar, Для меня это означает, что foo а также bar вероятно, не так много общего.

Вот как бы я изменил ваш пример: (при условии foo а также bar не имеет ничего общего)

public class fooController
{
    private foo fooInstance;

    public fooController() {
        fooInstance = new foo
    }

    public void fooAction1(int arg){
        this.foo.foo3(arg);
    }

    public void fooAction2(){
        this.foo.foo1();
    }
}

public class barController 
{

    private bar barInstance;

    public bazController(){
        this.barInstance = new bar();
    }

    public void barAction1(int arg){
         this.bar.bar3(arg);
    }

    public void barAction2(){
         this.bar.bar1();
    }
}

РЕДАКТИРОВАТЬ
Пример, где у вас будет контроллер, который делегирует более чем один экземпляр бизнес-логики, может выглядеть примерно так:

public class UserSettingsController
{
    private UserAddressLogic addressLogic;
    private UserPersonalInfoLogic personalInfoLogic;

    public UserSettingsController() {
        addressLogic = new UserAddressLogic();
        personalInfoLogic = new UserPersonalInfoLogic();
    }

    public User GetUser() {
        User user = new User();
        user.Address = addressLogic.GetUserAddress();
        user.PersonalInfo = personalInfoLogic.GetPersonalInfo();

        return user;
    }
}
Другие вопросы по тегам