Quando mover um campo comum para uma classe base?


16

Atualmente, tenho duas classes derivadas, Ae Bambas têm um campo em comum e estou tentando determinar se deve subir na classe base.

Ela nunca é referenciada a partir da classe base e diz que, em algum momento no caminho, outra classe é derivada, Cque não possui um _field1, então o principal dos "menos privilegiados" (ou algo) não seria violado se foi?

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}

18
Eu acho que esta questão não é clara porque você não nos deram nenhuma idéia do que Base, A, B, C, e _field1são. Esses são detalhes importantes que não devem ser deixados de fora; Eu acho que você deve editar a pergunta para falar sobre o que são.
quer

Com base nas respostas, eu: reconstruiria o veículo para ter uma suspensão virtual; então, carro e bicicleta poderiam ter rodas e o barco poderia ter flutuabilidade, o que moverá a abstração para cima. Acho que se minha abstração leva diretamente a configurações específicas, não mudei o conceito suficientemente longe na cadeia.
Patrick Hughes

6
Não use herança de classe para evitar a duplicação de código. Use-o para herdar e estender o comportamento , ou seja, polimorfismo. Mova um campo comum para uma classe base se, e somente se , for logicamente o mesmo campo, não duas informações não relacionadas que compartilham o mesmo nome em seus respectivos contextos.
Brandon

Por que você tem uma classe base para começar?
Jpmc26

Respostas:


34

Tudo depende do problema exato que você está tentando resolver.

Considere um exemplo concreto: sua classe base abstrata é Vehiclee você tem atualmente as implementações concretas Bicyclee Car. Você está pensando em mudar numberOfWheelsde Bicyclee Carpara veículo. Você deveria fazer isso? Não! Porque nem todos os veículos têm rodas. Você já pode dizer que, se tentar adicionar uma Boatclasse, ela será interrompida.

Agora, se sua classe base abstrata era WheeledVehicle, é lógico ter a numberOfWheelsvariável membro lá.

Você precisa aplicar a mesma lógica ao seu problema, porque, como você pode ver, não é uma resposta simples, sim ou não.


3
Pode-se aceitar temporariamente que 0 é um número válido de Off Wheels. No entanto, eventualmente, você pode adicionar um roll()método, no ponto em que a ideia da subclasse parece presciente.
user949300

11
Um barco tem 0 rodas. O que isso quebra?
precisa saber é o seguinte

14
@DDrmmr Não é que um barco tenha 0 rodas, é que as rodas nem sequer existem como conceito para um barco - portanto, seus modelos não devem permitir isso.
Peter M

10
Meu argumento é que o exemplo é ruim. Não há nada errado conceitualmente com um veículo (que é um barco) afirmando que ele tem 0 rodas.
precisa saber é o seguinte

10
Então tudo vai para o inferno quando você precisa guardar um barco a remo.
precisa saber é o seguinte

13

Logicamente falando, além de colocar o campo replicado nas subclasses vs. em comum na classe base, existe uma terceira opção: introduzir uma nova subclasse na hierarquia que possua as propriedades comuns entre as duas. @ Peter sugere isso sem ir totalmente para lá.

Usando o exemplo de @ Pete, introduziríamos uma subclasse (possivelmente abstrata) para Veículo com Rodas que desce da classe base original - enquanto as duas subclasses descem dela. Assim, a classe base original não é poluída com rodas, mas a semelhança entre as rodas é SECA (não repetida entre as subclasses que possuem rodas).

Obviamente, isso pode ser um exagero para seus propósitos, mas isso é suportado pelo mecanismo de hierarquia de classes.


Na verdade, é isso que eu decidi fazer (A e B se sobrepõem principalmente, então B será derivado de A).
samis 4/01/19

9

Vou bancar o advogado do diabo aqui.

Agora você não deve fazer nada .

É SECO? Não. Mas é melhor ter uma pequena duplicação do que uma abstração prematura da qual você não pode desistir facilmente mais tarde. O refator para mover uma propriedade para uma classe base comum é fácil. Indo para o outro lado não é. Espere e veja.

Ao tomar esse tipo de decisão, costumo usar uma "regra de 3": depois de repetir a mesma coisa em, por exemplo, três lugares diferentes, e só então, considero movê-la pela cadeia. NB você está apenas em 2.


2
Uma observação sábia, eu diria, necessária para tomar a decisão.
Radarbob

1
Eu concordo principalmente, mas "No momento" (sem código extra como o que vemos) a refatoração em ambas as direções é trivial. Porém, se houver código adicional que use o campo, a refatoração em ambas as direções poderá se tornar significativamente mais difícil.
Doc Brown

2

Em geral, eu o moveria para a classe base. Não acho que exista um objetivo sim / não, porque há uma troca aqui - transportar campos não utilizados versus reduzir a complexidade.

Normalmente, prefiro classes base 'pesadas' que contêm qualquer coisa que possa ser compartilhada. Isso simplifica a serialização de arquivos, pois você não precisa de métodos de serialização descendentes em todas as classes derivadas. Mas se você não tiver esse problema ou um problema semelhante, ou talvez precise fazer tudo o que puder para reduzir o uso de memória, apenas os campos em que você precisa devem ficar bem.

Uma classe 'intermediária' que introduz os campos comuns será boa se você tiver um número muito limitado de campos. Mas esteja ciente de que a abordagem pode aumentar drasticamente a complexidade se você tiver dezenas de campos usados ​​em combinações diferentes, levando a muitas classes intermediárias, cada uma introduzindo um conjunto específico de campos. Isso pode se tornar um problema de manutenção.


Meu exemplo é trivial, embora ainda seja um código de produção. Você faz um bom argumento para "comprometer" a hierarquia com uma classe base "pesada", à qual eu também me veria inclinando-se nesse caso.
samis 4/01/19

1
@ samis: você usa classes nomeadas "A, B, C" e "Base" com apenas um campo e nenhum método no código de produção? Eu questiono isso.
Doc Brown
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.