Твердый образец регулятора 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;
}
}