O Princípio da Responsabilidade Única declara que "uma classe deve ter um motivo para a mudança".
No padrão MVC, o trabalho do Controlador é mediar entre a Visualização e o Modelo. Ele oferece uma interface para o View relatar ações feitas pelo usuário na GUI (por exemplo, permitindo que o View chame controller.specificButtonPressed()
) e pode chamar os métodos apropriados no Modelo para manipular seus dados ou invocar suas operações (por exemplo model.doSomething()
) .
Isso significa que:
- O Controller precisa conhecer a GUI, a fim de oferecer ao View uma interface adequada para relatar ações do usuário.
- Ele também precisa conhecer a lógica do Modelo, para poder invocar os métodos apropriados no Modelo.
Isso significa que há duas razões para mudar : uma alteração na GUI e uma alteração na lógica de negócios.
Se a GUI mudar, por exemplo, um novo botão for adicionado, o Controlador poderá precisar adicionar um novo método para permitir que a View relate um usuário pressionando esse botão.
E se a lógica de negócios no Modelo mudar, o Controlador poderá ter que mudar para invocar os métodos corretos no Modelo.
Portanto, o controlador tem dois motivos possíveis para mudar . Isso quebra o SRP?
fonte
Respostas:
Se você continuar, consequentemente, discutindo sobre o SRP, perceberá que "responsabilidade única" é na verdade um termo esponjoso. Nosso cérebro humano é de alguma maneira capaz de distinguir entre responsabilidades diferentes e múltiplas responsabilidades podem ser abstraídas em uma responsabilidade "geral". Por exemplo, imagine que em uma família comum de quatro pessoas exista um membro da família responsável por fazer o café da manhã. Agora, para fazer isso, é necessário ferver ovos e torradas de pão e, é claro, preparar uma xícara saudável de chá verde (sim, o melhor é o chá verde). Dessa forma, você pode dividir "fazendo café da manhã" em pedaços menores, que são abstraídos para "fazer café da manhã". Observe que cada peça também é uma responsabilidade que pode, por exemplo, ser delegada a outra pessoa.
Voltando ao MVC: se mediar entre modelo e exibição não é uma responsabilidade, mas duas, então qual seria a próxima camada de abstração acima, combinando essas duas? Se você não consegue encontrar um, não o abstrai corretamente ou não existe nenhum, o que significa que você acertou tudo. E eu sinto que é o caso de um controlador, lidando com uma visão e um modelo.
fonte
Se uma classe tem "duas razões possíveis para mudar", sim, ela viola o SRP.
Um controlador geralmente deve ser leve e ter a responsabilidade única de manipular o domínio / modelo em resposta a algum evento controlado por GUI. Podemos considerar cada uma dessas manipulações como basicamente casos de uso ou recursos.
Se um novo botão for adicionado à GUI, o controlador deverá mudar apenas se esse novo botão representar algum novo recurso (ou seja, oposto ao mesmo botão que existia na tela 1, mas ainda não existia na tela 2, e é então adicionado à tela 2). Também seria necessário haver uma nova alteração correspondente no modelo, para suportar essa nova funcionalidade / recurso. O controlador ainda tem a responsabilidade de manipular o domínio / modelo em resposta a algum evento controlado por GUI.
Se a lógica de negócios do modelo for alterada devido à correção de um bug e exigir que o controlador seja alterado, esse é um caso especial (ou talvez o modelo esteja violando o principal aberto-fechado). Se a lógica de negócios no modelo mudar para oferecer suporte a alguma nova funcionalidade / recurso, isso não afetará necessariamente o controlador - apenas se o controlador precisar expor esse recurso (o que quase sempre seria o caso, caso contrário, por que ele seria adicionado a o modelo de domínio, se não for usado). Portanto, neste caso, o controlador também deve ser modificado, para suportar a manipulação do modelo de domínio dessa nova maneira, em resposta a algum evento controlado por GUI.
Se o controlador tiver que mudar porque, digamos, a camada de persistência é alterada de um arquivo simples para um banco de dados, o controlador certamente está violando o SRP. Se o controlador sempre trabalha na mesma camada de abstração, isso pode ajudar a alcançar o SRP.
fonte
O controlador não viola o SRP. Como você afirma, sua responsabilidade é mediar entre os modelos e a visualização.
Dito isto, o problema com o seu exemplo é que você está vinculando os métodos do controlador à lógica na visualização, ou seja
controller.specificButtonPressed
. Nomeando os métodos dessa maneira, vincula o controlador à sua GUI, você não conseguiu abstrair as coisas corretamente. O controlador deve executar ações específicas,controller.saveData
ou seja, oucontroller.retrieveEntry
. Adicionar um novo botão na GUI não significa necessariamente adicionar um novo método ao controlador.Pressionar um botão na visualização significa fazer alguma coisa, mas o que quer que seja poderia facilmente ter sido acionado de várias maneiras ou mesmo não através da visualização.
No artigo da Wikipedia sobre SRP
O controlador não está preocupado com o que está na exibição apenas quando um de seus métodos é chamado, ele fornece dados especificados para a exibição. Ele só precisa saber sobre a funcionalidade do modelo, desde que saiba que precisa chamar os métodos que eles terão. Não sabe nada além disso.
Saber que um objeto tem um método disponível para chamar não é o mesmo que conhecer sua funcionalidade.
fonte
specificButtonsPressed()
é porque li que a visualização não deveria saber nada sobre a funcionalidade dos botões e outros elementos da GUI. Fui ensinado que, quando um botão é pressionado, a exibição deve simplesmente se reportar ao controlador, e o controlador deve decidir 'o que significa' (e depois invocar os métodos apropriados no modelo). Fazer a chamada de visualizaçãocontroller.saveData()
significa que a visualização precisa saber o que significa pressionar esse botão, além do fato de ter sido pressionado.specificButtonPressed()
), na verdade o controlador não estaria tão ligado à GUI. Devo abandonar osspecificButtonPressed()
métodos? A vantagem que acho que ter esses métodos faz sentido para você? Ou terbuttonPressed()
métodos no controlador não vale a pena?specificButtonPressed()
métodos no controlador é que ele separa a View do significado de pressionar o botão completamente . No entanto, a desvantagem é que ele vincula o controlador à GUI em certo sentido. Qual abordagem é melhor?foo
ou com a mesma facilidadefireZeMissiles
. Ele saberá apenas que deve reportar a uma função específica. Ele não sabe o que a função faz, apenas a chamará. O controlador não está preocupado com a forma como seus métodos são chamados, apenas que ele responderá de uma certa maneira quando for.Uma responsabilidade única dos controladores é o contrato que medeia entre a visualização e o modelo. A Visualização deve ser responsável apenas pela exibição, o modelo deve ser responsável apenas pela lógica de negócios. É responsabilidade dos controladores colmatar essas duas responsabilidades.
Tudo bem, mas se afastar um pouco da academia; um controlador no MVC geralmente é composto por muitos métodos de ação menores. Essas ações geralmente correspondem a coisas que uma coisa pode fazer. Se estou vendendo produtos, provavelmente terei um ProductController. Esse controlador terá ações como GetReviews, ShowSpecs, AddToCart ect ...
O modo de exibição tem o SRP de exibição da interface do usuário e parte dessa interface inclui um botão que diz AddToCart.
O controlador tem o SRP de conhecer todas as visualizações e modelos envolvidos no processo.
A ação AddToCart dos controladores tem o SRP específico de conhecer todos que precisam estar envolvidos quando um item é adicionado a um carrinho.
O Modelo de Produto possui o SRP da modelagem da lógica do produto e o ShoppingCart Model possui o SRP da modelagem de como os itens são salvos para check-out posterior. O Modelo do Usuário possui um SRP para modelar o usuário que está adicionando itens ao carrinho.
Você pode e deve reutilizar modelos para realizar seus negócios e esses modelos precisam ser acoplados em algum momento do seu código. O controlador controla cada maneira única em que o acoplamento acontece.
fonte
Na verdade, os controladores têm apenas uma responsabilidade: alterar o estado dos aplicativos com base na entrada do usuário.
source: wikipedia
Se você está tendo "controladores" no estilo Rails (que manipulam instâncias de registro ativas e modelos burros) , é claro que estão quebrando o SRP.
Por outro lado, os aplicativos no estilo Rails não são realmente MVC para começar.
fonte