Gostaria de saber o que é melhor em termos de bom design de OOP, código limpo, flexibilidade e evitar odores de código no futuro. Situação da imagem, na qual você tem muitos objetos muito semelhantes que precisa representar como classes. Essas classes não possuem nenhuma funcionalidade específica, apenas classes de dados e são diferentes apenas pelo nome (e contexto) Exemplo:
Class A
{
String name;
string description;
}
Class B
{
String name;
String count;
String description;
}
Class C
{
String name;
String count;
String description;
String imageUrl;
}
Class D
{
String name;
String count;
}
Class E
{
String name;
String count;
String imageUrl;
String age;
}
Seria melhor mantê-los em classes separadas, para obter legibilidade "melhor", mas com muitas repetições de código, ou seria melhor usar a herança para ser mais SECA?
Ao usar a herança, você terá algo parecido com isto, mas os nomes de classe perderão o significado contextual (por causa do is-a, não has-a):
Class A
{
String name;
String description;
}
Class B : A
{
String count;
}
Class C : B
{
String imageUrl;
}
Class D : C
{
String age;
}
Sei que a herança não é e não deve ser usada para a reutilização de código, mas não vejo outra maneira possível de reduzir a repetição de código nesse caso.
fonte
Exatamente. Veja isso, fora de contexto:
Quais propriedades um D tem? Você consegue se lembrar? E se você complicar ainda mais a hierarquia:
E se, horror após horrores, você deseja adicionar um campo imageUrl a F, mas não a E? Você não pode derivar de C e E.
Eu vi uma situação real em que muitos tipos diferentes de componentes tinham nome, ID e descrição. Mas isso não era da natureza de serem componentes, era apenas uma coincidência. Cada um tinha um ID porque eles foram armazenados em um banco de dados. O nome e a descrição foram exibidos.
Os produtos também tinham um ID, Nome e Descrição, por motivos semelhantes. Mas eles não eram componentes, nem eram produtos de componentes. Você nunca veria as duas coisas juntas.
Mas, alguns desenvolvedores leram sobre o DRY e decidiram que ele removeria toda sugestão de duplicação do código. Então, ele chamou tudo de produto e acabou com a necessidade de definir esses campos. Eles foram definidos em Produto e tudo que precisava desses campos poderia derivar de Produto.
Não posso dizer isso com força suficiente: essa não é uma boa ideia.
DRY não se trata de remover a necessidade de propriedades comuns. Se um objeto não for um Produto, não o chame de Produto. Se um Produto não EXIGIR uma Descrição, pela própria natureza de ser um Produto, não defina Descrição como uma Propriedade do Produto.
Por fim, aconteceu que tínhamos Componentes sem descrições. Então começamos a ter descrições nulas nesses objetos. Não anulável. Nulo. Sempre. Para qualquer produto do tipo X ... ou posterior Y ... e N.
Esta é uma violação flagrante do princípio da substituição de Liskov.
DRY é sobre nunca se colocar em uma posição em que você pode corrigir um bug em um lugar e esquecer de fazê-lo em outro lugar. Isso não vai acontecer porque você tem dois objetos com a mesma propriedade. Nunca. Então não se preocupe.
Se o contexto das classes torna óbvio que você deveria, o que será muito raro, então e somente então você deve considerar uma classe pai comum. Mas, se for propriedades, considere por que você não está usando uma interface.
fonte
A herança é uma maneira de obter um comportamento polimórfico. Se suas classes não têm nenhum comportamento, a herança é inútil. Nesse caso, eu nem os consideraria objetos / classes, mas estruturas.
Se você quiser colocar estruturas diferentes em diferentes partes do seu comportamento, considere interfaces com métodos ou propriedades get / set, como IHasName, IHasAge, etc. Isso tornará o design muito mais limpo e permitirá uma melhor composição destes. tipo de hiearchies.
fonte
Não é para isso que servem as interfaces? Classes não relacionadas com funções diferentes, mas com uma propriedade semelhante.
fonte
Sua pergunta parece estar enquadrada no contexto de um idioma que não suporta herança múltipla, mas não especifica isso especificamente. Se você estiver trabalhando com um idioma que suporta herança múltipla, isso se tornará trivialmente fácil de resolver com apenas um único nível de herança.
Aqui está um exemplo de como isso pode ser resolvido usando herança múltipla.
fonte