Pergunta

Isso é um pouco de uma pergunta para este pergunta.

Suponhamos que eu tenha uma árvore de herança da seguinte forma:

Car -> Ford -> Mustang -> MustangGT

Há um benefício para a definição de interfaces para cada estas classes?Exemplo:

ICar -> IFord -> IMustang -> IMustangGT

Eu posso ver que talvez outras classes (como Chevy) gostaria de implementar Icar ou IFord e talvez até mesmo IMustang, mas , provavelmente, não IMustangGT porque ele é tão específico.São as interfaces supérfluo neste caso?

Também, eu acho que qualquer classe que gostaria de implementar IFord com certeza gostaria de deseja usar a sua herança, por herança do Ford para não duplicar código.Se isso é um dado, qual é a vantagem de também de execução IFord?

Foi útil?

Solução

Na minha experiência, as interfaces são mais utilizados quando você tem várias classes que cada um precisa responder para o mesmo método, ou métodos, de modo que eles podem ser usados de forma intercambiável por outro código que será escrito contra aqueles das classes de interface comum.O melhor uso de uma interface é quando o protocolo é importante, mas a lógica subjacente pode ser diferente para cada classe.Se você de outra forma seria a duplicação de lógica, considerar classes abstratas ou padrão de herança de classe em vez disso.

E em resposta à primeira parte da sua pergunta, eu recomendaria contra a criação de uma interface para cada uma de suas classes.Este seria desnecessariamente a desorganização de sua estrutura de classes.Se você achar que você precisa de uma interface que você pode sempre adicionar mais tarde.Espero que isso ajude!

Adam

Outras dicas

Eu também concordo com Resposta de Adamalex que as interfaces devem ser compartilhadas por classes que devem responder a determinados métodos.

Se as classes tiverem funcionalidade semelhante, ainda não estão diretamente relacionadas entre si em um relacionamento ancestral, uma interface seria uma boa maneira de adicionar essa função às classes sem duplicar a funcionalidade entre os dois. (Ou tenha várias implementações com apenas diferenças sutis.)

Enquanto estamos usando uma analogia de carro, um exemplo concreto. Digamos que tenhamos as seguintes aulas:

Car -> Ford   -> Escape  -> EscapeHybrid
Car -> Toyota -> Corolla -> CorollaHybrid

Carros têm wheels e pode Drive() e Steer(). Portanto, esses métodos devem existir no Car classe. (Provavelmente o Car A classe será uma classe abstrata.)

Descendo a linha, temos a distinção entre Ford e Toyota (Provavelmente implementado como diferença no tipo de emblema no carro, provavelmente provavelmente uma classe abstrata.)

Então, finalmente temos um Escape e Corolla classe que são classes completamente implementadas como carro.

Agora, como poderíamos fazer um Híbrido veículo?

Poderíamos ter uma subclasse de Escape isso é EscapeHybrid que adiciona um FordsHybridDrive() método e uma subclasse de Corolla isso é CorollaHybrid com ToyotasHybridDrive() método. Os métodos estão basicamente fazendo a mesma coisa, mas ainda temos métodos diferentes. Que nojo. Parece que podemos fazer melhor do que isso.

Digamos que um híbrido tem um HybridDrive() método. Como não queremos acabar tendo dois tipos diferentes de híbridos (em um mundo perfeito), para que possamos fazer um IHybrid interface que tem um HybridDrive() método.

Então, Se queremos fazer um EscapeHybrid ou CorollaHybrid classe, tudo o que temos que fazer é implementar o IHybrid interface.

Para um exemplo do mundo real, vamos dar uma olhada em Java. Uma classe que pode fazer uma comparação de um objeto com outro objeto implementa o Comparable interface. Como o nome indica, a interface deve ser para uma classe que é comparável, daí o nome "comparável".

Apenas como uma questão de interesse, um Exemplo de carro é usado no Interfaces Lição do Java Tutorial.

Você não deve implementar nenhuma dessas interfaces.

A herança de classe descreve que objeto é (por exemplo: é identidade). Tudo bem, no entanto, na maioria das vezes, que objeto é, é muito menos importante do que um objeto faz. É aqui que entra as interfaces.

Uma interface deve descrever que objeto faz), ou como ele age. Com isso, quero dizer seu comportamento e o conjunto de operações que fazem sentido, dado esse comportamento.

Como tal, bons nomes de interface geralmente devem ser da forma IDriveable, IHasWheels, e assim por diante. Às vezes, a melhor maneira de descrever esse comportamento é referenciar um outro objeto bem conhecido, para que você possa dizer "age como um deles" (por exemplo: IList) Mas IMHO essa forma de nomeação é em minoria.

Dada essa lógica, os cenários onde herança da interface faz sentido ser completamente e totalmente diferente dos cenários onde herança do objeto Faz sentido - muitas vezes esses cenários não se relacionam um com o outro.

Espero que ajude você a pensar nas interfaces que você realmente precisa :-)

Eu diria que só fazia uma interface para as coisas que você precisa se referir. Você pode ter outras classes ou funções que precisam saber sobre um carro, mas com que frequência haverá algo que precisa saber sobre um Ford?

Não construa coisas que você não precisa. Se você precisa das interfaces, é um pequeno esforço para voltar e construí -las.

Além disso, do lado pedante, espero que você não esteja realmente construindo algo que se parece com essa hierarquia. Não é para isso que a herança deve ser usada.

Crie -o apenas quando esse nível de funcionalidade se tornar necessário.

O código de reforma está sempre no processo contínuo.

Existem ferramentas disponíveis que permitirão extrair a interface, se necessário. POR EXEMPLO http://geekswithblogs.net/jaysmith/archive/2008/02/27/refactor-visual-studio-extract-interface.aspx

Faça um ICAR e todo o restante (Make = Ford, Model = Mustang e outras coisas) como membros de uma classe que implementa a interface.

Você pode querer ter sua aula Ford e, por exemplo Make == Whatever, isso depende do seu estilo.

De qualquer forma - na minha opinião, esses são atributos de um carro e não o contrário - você só precisa de uma interface porque os métodos são comuns: freio, aceleração, etc.

O Ford pode fazer coisas que outros carros não podem? Eu não acho.

Eu crio os dois primeiros níveis, Icar e Iford e deixo o segundo nível em paz até que eu precise de uma interface nesse segundo nível.

Pense cuidadosamente sobre como seus objetos precisam interagir um com o outro no domínio do seu problema e considere se você precisa ter mais de uma implementação de um conceito abstrato específico. Use interfaces para fornecer um contrato em torno de um conceito com o qual outros objetos interagem.

No seu exemplo, sugiro que a Ford seja provavelmente um fabricante e o Mustang é um valor de nome do modelo usado pelo fabricante Ford; portanto, você pode ter algo mais como:

Ivehichle -> Carimpl, MotorbikeImpl -O fabricante Has -A Has -Many ModelNames

Nesta resposta sobre o diferença entre interface e classe, Eu expliquei que:

  • interface expõe que conceito é (em termo de "o que é"Válido, no momento da compilação), e é usado para valores (Myinterface x = ...)
  • classe expõe o que um conceito faz (na verdade executado no tempo de execução) e é usado para valores ou objetos (myclass x ou amyclass.method ()))

Portanto, se você precisar armazenar em uma variável 'Ford' (noção de 'valor') diferentes subclasses de Ford, crie um iford. Caso contrário, não se preocupe até que você realmente precise.

Esse é um critério: se não for atendido, Iford provavelmente é inútil.
Se for atendido, os outros critérios expostos nas respostas anteriores se aplicam: Se um Ford tiver uma API mais rica que um carro, um IFORD será útil para fins de polimorfismos. Caso contrário, o ICAR é suficiente.

Na minha opinião, as interfaces são uma ferramenta para aplicar um requisito de que uma classe implemente uma certa assinatura ou (como eu gosto de pensar nisso) um certo "comportamento" para mim, acho que se a capital I no início dos meus nomes de naterface como Um pronome pessoal, e eu tento nomear minhas interfaces para que elas possam ser lidas dessa maneira ... ICANFLY, IKnowHowtopersistMySelf Iamdisplayable, etc ... Então, no seu exemplo, eu não criaria uma interface para refletir a assinatura pública completa de qualquer específico classe. Eu analisaria a assinatura pública (o comportamento) e depois separaria os membros em grupos lógicos menores (quanto menor, melhor) (usando seu exemplo) imove, iusefuel, icarrypassangers, iserable, iaccelate, idepreciado, etc ... e depois aplicar essas interfaces para quaisquer outras classes no meu sistema precisam delas

Em geral, a melhor maneira de pensar sobre isso (e muitas perguntas no OO) é pensar na noção de contrato.

Um contrato é definido como um contrato entre duas (ou mais) partes, que declara obrigações específicas que cada parte deve cumprir; Em um programa, é isso que os serviços que uma classe fornecerá e o que você deve fornecer à classe para obter os serviços. Uma interface indica um contrato que qualquer classe que implemente a interface deve satisfazer.

Com isso em mente, porém, sua pergunta depende do idioma que você está usando e do que deseja fazer.

Depois de muitos anos fazendo OO (como, oh meu Deus, 30 anos), eu normalmente escreveria uma interface para cada contrato, especialmente em Java, porque isso facilita muito os testes: se eu tiver uma interface para a classe, posso construir objetos simulados com facilidade, quase trivialmente.

As interfaces devem ser uma API pública genérica, e os usuários serão restritos ao uso desta API pública. A menos que você pretenda que os usuários usem os métodos específicos de tipo de IMustangGT, você pode querer limitar a hierarquia da interface a ICar e IExpensiveCar.

Somente herdar de interfaces e classes abstratas.

Se você tiver algumas classes, o que é quase o mesmo e precisa implementar a maioria dos métodos, o uso e a interface em combinação com a compra do outro objeto.
Se as classes do Mustang forem tão diferentes, não apenas crie uma interface ICAR, mas também Imustang.
Portanto, a classe Ford e Mustang podem herdar do ICAR, e Mustang e Mustanggt do ICAR e Imustang.

Se você implementar a classe Ford e um método é o mesmo que o Mustang, compre da Mustang:

class Ford{
  public function Foo(){
    ...
    Mustang mustang  = new Mustang();
    return mustang.Foo();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top