Parece que as respostas dos dois lados da cerca podem ser resumidas aqui:
Design well, and put interfaces where interfaces are needed.
Como observei na minha resposta à resposta de Yanni , não acho que você possa ter dificuldades e regra rápida sobre interfaces. A regra precisa ser, por definição, flexível. Minha regra nas interfaces é que uma interface deve ser usada em qualquer lugar em que você esteja criando uma API. E uma API deve ser criada em qualquer lugar que você esteja cruzando a fronteira de um domínio de responsabilidade para outro.
Para um exemplo (horrivelmente inventado), digamos que você esteja criando uma Car
de classe. Na sua turma, você certamente precisará de uma camada de interface do usuário. Nesse exemplo específico, ele assume a forma de IginitionSwitch
, SteeringWheel
, GearShift
, GasPedal
e BrakePedal
. Como esse carro contém um AutomaticTransmission
, você não precisa de ClutchPedal
. (E como este é um carro terrível, não há A / C, rádio ou assento. Na verdade, as tábuas do assoalho estão faltando também - você só precisa segurar o volante e esperar o melhor!)
Então, qual dessas classes precisa de uma interface? A resposta poderia ser todas elas, ou nenhuma delas - dependendo do seu design.
Você poderia ter uma interface assim:
Interface ICabin
Event IgnitionSwitchTurnedOn()
Event IgnitionSwitchTurnedOff()
Event BrakePedalPositionChanged(int percent)
Event GasPedalPositionChanged(int percent)
Event GearShiftGearChanged(int gearNum)
Event SteeringWheelTurned(float degree)
End Interface
Nesse ponto, o comportamento dessas classes torna-se parte da Interface ICabin / API. Neste exemplo, as classes (se houver alguma) são provavelmente simples, com algumas propriedades e uma ou duas funções. E o que você está implicitamente afirmando com seu design é que essas classes existem apenas para suportar qualquer implementação concreta do ICabin que você tenha, e elas não podem existir sozinhas, ou elas são sem sentido fora do contexto da ICabin.
É a mesma razão pela qual você não testa membros privados - eles existem somente para suportar a API pública e, portanto, seu comportamento deve ser testado testando a API.
Portanto, se a sua classe existe somente para oferecer suporte a outra classe e, conceitualmente, você a vê como não tendo realmente um domínio próprio, não há problema em pular a interface. Mas se a sua turma é importante o suficiente para você considerar que ela cresceu o suficiente para ter seu próprio domínio, vá em frente e forneça uma interface para ela.
EDITAR:
Freqüentemente (incluindo nesta resposta) você lerá coisas como 'domínio', 'dependência' (frequentemente associadas a 'injeção') que não significam nada quando você está começando a programar não significou nada para mim). Para domínio, significa exatamente o que parece:
The territory over which dominion or authority is exerted;
the possessions of a sovereign or commonwealth, or the
like. Also used figuratively. [WordNet sense 2]
[1913 Webster]
Nos termos do meu exemplo, vamos considerar o IgnitionSwitch
. Em um carro do espaço, o interruptor de ignição é responsável por:
- Autenticando (não identificando) o usuário (eles precisam da chave correta)
- Fornecendo corrente ao acionador de partida para que ele possa realmente ligar o carro
- Fornecendo corrente ao sistema de ignição para que ele possa continuar a operar
- Desligar a corrente para que o carro pare.
- Dependendo de como você o visualiza, na maioria (todos?) carros mais novos há um interruptor que impede que a chave seja removida da ignição enquanto a transmissão está fora do Parque, portanto, isso pode fazer parte de seu domínio. (Na verdade, isso significa que eu preciso repensar e redesenhar meu sistema ...)
Essas propriedades formam o domínio do IgnitionSwitch
ou, em outras palavras, o que ele conhece e é responsável.
O IgnitionSwitch
não é responsável pelo GasPedal
. O interruptor de ignição é completamente ignorante do pedal do acelerador em todos os sentidos. Ambos operam completamente independentes um do outro (apesar de um carro ser bastante inútil sem os dois!).
Como afirmei originalmente, isso depende do seu design. Você pode criar um IgnitionSwitch
que tenha dois valores: Ativado ( True
) e Desativado ( False
). Ou você pode projetá-lo para autenticar a chave fornecida e uma série de outras ações. Essa é a parte difícil de ser um desenvolvedor que está decidindo onde desenhar as linhas na areia - e honestamente a maior parte do tempo é completamente relativo. No entanto, essas linhas na areia são importantes - é aí que está sua API e, portanto, onde devem estar suas interfaces.