Pergunta

Em um projeto, nossa equipe está usando listas de objetos para realizar operações em massa em conjuntos de dados que deveriam ser todos processados ​​de maneira semelhante.Em particular, idealmente, objetos diferentes agiriam da mesma forma, o que seria facilmente alcançado com o polimorfismo.O problema que tenho com isso é que a herança implica a é um relacionamento, em vez de tem um relação.Por exemplo, vários objetos tenha um contador de danos, mas para facilitar o uso em uma lista de objetos, o polimorfismo poderia ser usado - exceto que isso implicaria um é um relacionamento que não seria verdade.(Uma pessoa não é um contador de danos.)

A única solução que consigo pensar é fazer com que um membro da classe retorne o tipo de objeto adequado quando convertido implicitamente, em vez de depender de herança.Seria melhor renunciar ao é um / tem um ideal em troca de facilidade de programação?

Editar:Para ser mais específico, estou usando C++, portanto, usar o polimorfismo permitiria que diferentes objetos "agissem da mesma forma", no sentido de que as classes derivadas poderiam residir em uma única lista e serem operadas por uma função virtual da classe base.O uso de uma interface (ou imitá-las via herança) parece uma solução que eu estaria disposto a usar.

Foi útil?

Solução

Isso pode ser feito usando a herança múltipla. No seu caso específico (C ++), você pode usar as classes virtuais puras como interfaces. Isso permite que você tem herança múltipla, sem criar problemas escopo / ambigüidade. Exemplo:

class Damage {
    virtual void addDamage(int d) = 0;
    virtual int getDamage() = 0;
};

class Person : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d * 2;
    }

    int getDamage() {
        return damage;
    }
};

class Car : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d;
    }

    int getDamage() {
        return damage;
    }
};

Agora, tanto Pessoa e Carro 'é-um' Damage, ou seja, eles implementar a interface danos. O uso de classes virtuais puras (de modo que eles são como as interfaces) é fundamental e deve ser usado com freqüência. Ele isola as mudanças futuras de alterar todo o sistema. Leia-se sobre o Princípio Open-Closed para mais informações.

Outras dicas

Eu acho que você deve ser implementação de interfaces para ser capaz de cumprir o seu tem um relações (estou fazendo isso em C #):

public interface IDamageable
{
    void AddDamage(int i);
    int DamageCount {get;}
}

Você poderia implementar isso em seus objetos:

public class Person : IDamageable

public class House : IDamageable

E você estaria certo de que a propriedade DamageCount e tem um método para permitir que você adicione danos, sem implicar que uma pessoa e uma casa são relacionados uns aos outros em algum tipo de hierarquia.

Eu concordo com Jon, mas supondo que você ainda tem necessidade de uma classe contra danos separado, você pode fazer:

class IDamageable {
  virtual DamageCounter* damage_counter() = 0;
};
class DamageCounter {
  ...
};

Cada classe damageable então precisa fornecer sua própria função membro damage_counter (). A desvantagem desta situação é que ele cria uma vtable para cada classe damageable. em vez disso você pode usar:

class Damageable {
 public:
  DamageCounter damage_counter() { return damage_counter_; }
 private:
  DamageCounter damage_counter_;
};

Mas muitas pessoas são não esfria com herança múltipla quando vários pais têm variáveis ??de membro.

Às vezes, vale a pena dar-se o ideal para o realista. Se isso vai causar um problema enorme para "fazê-lo direito" sem nenhum benefício real, então eu faria isso errado. Com isso dito, muitas vezes eu acho que vale a pena tomar o tempo para fazê-lo bem, porque desnecessário múltipla complexidade herança aumenta, e pode contribuir para o sistema ser menos sustentável. Você realmente tem que decidir o que é melhor para a sua circunstância.

Uma opção seria ter esses objetos implementar uma interface Damageable, ao invés de herdar de DamageCounter. Desta forma, uma pessoa tem-um marcador de dano, mas é damageable. (Muitas vezes eu achar interfaces de fazer muito mais sentido como adjetivo do que substantivos.) Em seguida, você poderia ter uma interface danos consistentes em objetos Damageable, e não expor que um contador de danos é a implementação subjacente (a menos que você precisa).

Se você quiser ir a rota modelo (assumindo C ++ ou similar), você poderia fazer isso com mixins, mas isso pode ficar feio muito rapidamente se feito mal.

Esta questão é realmente confuso: /

A sua questão em negrito é muito aberto e tem uma resposta de "depende", mas o seu exemplo realmente não dá muita informação sobre o contexto em que você está pedindo. Estas linhas me confundem;

conjuntos de dados que devem ser todos tratados de forma semelhante

O que maneira? São os conjuntos processados ??por uma função? Outra classe? Via uma função virtual sobre os dados?

Em particular, diferentes objetos ideal seria agir da mesma, o que seria muito facilmente alcançado com o polimorfismo

O ideal de "agindo da mesma" e polimorfismo são absolutamente independentes. Como é que o polimorfismo torná-lo fácil de conseguir?

@ Kevin

Normalmente, quando falamos de 'é um' vs 'tem um' estamos falando de Herança vs Composição.

Um ... marcador de dano seria apenas atributo de uma das suas classes derivadas e não seria realmente ser discutido em termos de 'Uma pessoa é um contador de danos' no que diz respeito à sua pergunta.

Ter o marcador de dano como um atributo não permite-lhe para diversos objetos com contadores de dano em uma coleção. Por exemplo, uma pessoa e um carro pode ambos têm contadores de dano, mas você não pode ter um vector<Person|Car> ou um vector<with::getDamage()> ou qualquer coisa semelhante na maioria dos idiomas. Se você tem uma classe base objeto comum, então você pode empurrá-los dessa maneira, mas então você não pode acessar o método getDamage() genericamente.

Essa foi a essência de sua pergunta, como eu lê-lo. "Devo violar is-a e has-a por causa do tratamento de certos objetos como se eles são os mesmos, embora eles não são?"

Normalmente, quando falamos de 'é um' vs 'tem um' estamos falando de Herança vs Composição.

Um ... marcador de dano seria apenas atributo de uma das suas classes derivadas e não seria realmente ser discutido em termos de 'Uma pessoa é um contador de danos' no que diz respeito à sua pergunta.

Veja este:

http://www.artima.com/designtechniques/compoinh.html

O que pode ajudá-lo ao longo do caminho.

@ Derek : a partir do texto, eu assumi há foi a clase base, tendo re-ler a pergunta eu meio que agora ver o que ele está chegando.

"Fazer certo" terá benefícios a longo prazo, mesmo que apenas porque alguém manter o sistema mais tarde vai encontrá-lo mais fácil de compreender se ele foi feito para a direita, para começar.

Dependendo do idioma, você pode muito bem ter a opção de herança múltipla, mas normalmente interfaces simples fazer mais sentido. Por "simples" Quero dizer fazer uma interface que não está tentando ser demais. É melhor ter um monte de interfaces simples e uns poucos monolíticas. Claro, há sempre um trade-off, e também muitas interfaces provavelmente levaria a que estão sendo "esquecidos" sobre ...

@ Andrew

O ideal de "agindo da mesma" e polimorfismo são absolutamente independentes. Como é que o polimorfismo torná-lo fácil de conseguir?

Eles todos têm, por exemplo, uma função em comum. Vamos chamá-lo addDamage(). Se você quer fazer algo como isto:

foreach (obj in mylist)
    obj.addDamage(1)

Em seguida, você precisa de uma linguagem dinâmica, ou você precisa deles para estender a partir de uma classe pai comum (ou interface). por exemplo:.

class Person : DamageCounter {}
class Car : DamageCounter {}

foreach (DamageCounter d in mylist)
    d.addDamage(1)

Em seguida, você pode tratar Person e Car o mesmo em certas circunstâncias muito úteis.

O polimorfismo não requer herança . Polimorfismo é o que você começa quando vários objetos implementar a mesma assinatura da mensagem (método).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top