Design: retornando à classe pai

13

Ao modelar um objeto com filhos, é comum incluir os filhos por meio da composição, como um membro da classe pai. Às vezes, porém, os filhos precisam dizer algo aos pais, eles precisam chamar uma função dos pais. Como isso pode ser feito usando C ++? Algumas opções são:

  1. Torne a classe pai global, portanto, os objetos filho poderão chamar funções de membro do objeto pai.

  2. Injete o objeto pai como um ponteiro ou referência em cada objeto filho. Então, quando o filho precisar informar algo ao objeto pai, ele sempre poderá fazê-lo porque possui uma variável de membro que pode usar.

Quais são os outros métodos para fazer isso? Existe um padrão geral de design ou nome para esse tipo de coisa?

Observe que estou interessado em idéias e soluções em C ++ porque os detalhes serão diferentes em outras linguagens orientadas a objetos. Por exemplo, o ponto 2 acima menciona 'ponteiros ou referências' e ambos são possíveis apenas em C ++. O C ++ possui recursos de linguagem que não estão presentes em outros idiomas; portanto, implementações de uma solução para o problema potencialmente incorporarão esses recursos de linguagem, tornando a solução diferente do que alguém pode inventar em outro idioma.

sashang
fonte
você pode adicionar um exemplo? Este é um exemplo válido para sua pergunta? Você tem um objeto de pedido (= pai) com itens de pedidos (filhos) e deseja atualizar o total do pedido quando uma quantidade de itens de pedido é alterada? ou está pensando em algo completamente diferente?
K3b
@ k3b Sim, esse é um exemplo válido. Algumas informações da criança mudaram, exigindo que os pais fizessem alguma coisa.
Sashang
basta adicionar alguns parâmetros de construtor e referenciar membros de dados a cada classe filho.
tp1
A criança precisa saber tudo sobre os pais ou seria simples delegate?
Julien Guertault

Respostas:

16

Primeiras coisas primeiro, isso pode ser um cheiro de código. O ponto de usar a composição para os pais / filhos é que os pais conhecem os filhos, mas não vice-versa. Especialmente se a relação é mais 'contém' do que 'é composta por'.

Uma referência ao pai é possível e bastante comum em C ++. Em outros idiomas, um objeto ou evento de função é mais frequentemente usado para permitir que a criança comunique coisas que pessoas de fora podem querer saber. Esse é um tipo comum de padrão de publicação-assinante. Eu suspeito que o que é mais idiomático depende da versão do C ++ que você está usando e dos padrões da sua base de código.

Telastyn
fonte
Na minha situação, é um cheiro de código. Ótima resposta.
Martin Pfeffer
3

Como outros já apontaram, a idéia básica de injetar o objeto pai como ponteiro ou referência é o caminho a seguir - em princípio.

Isso tem uma desvantagem: você obtém uma dependência cíclica entre o pai e o filho. Se você quiser evitar isso, defina uma classe base abstrata (uma interface) IParentda qual seu pai herda. IParentdeve conter os métodos como funções virtuais que a criança deseja chamar. Em seguida, injete o pai como uma referência a IParent. Isso facilita muito o teste de unidade do filho, pois agora você pode substituir o objeto pai facilmente por um objeto simulado.

Se seu filho precisar chamar apenas uma função do objeto pai, uma IParentclasse completa poderá ser superdimensionada. Nesse caso, será suficiente injetar um ponteiro para a função de membro no filho, ou um objeto de functor que encapsule essa função de membro.

Doc Brown
fonte
2

O que você pode fazer é manter uma referência ao pai na classe filho, por composição. Dessa forma, a criança conhece seus pais e pode invocar métodos públicos.

Portanto, eu iria com a opção 2. Você precisa ter cuidado, porém, quando um filho é removido do pai, precisa remover a referência ao pai no filho e apontá-la para nulo (ou um novo pai, se ele tiver 1). Ou você pode simplesmente excluir o objeto filho, dependendo do contexto.

marco-fiset
fonte
1

Passe-lhes uma referência ou um ponteiro para o pai. Você pode torná-los amigos dos pais ou tornar público o método chamado. Se você não quiser fazer nenhuma das opções acima, pode passar a eles um objeto "bridge" que expõe um dos métodos dos pais como público e é uma classe privada aninhada dos pais (portanto, ele tem acesso a todos os métodos pais) ) No entanto, isso pode ser um pouco complexo em muitas situações.

quant_dev
fonte
1

2) Injete o objeto pai como um ponteiro ou referência em cada objeto filho. Então, quando o filho precisar informar algo ao objeto pai, ele sempre poderá fazê-lo porque possui uma variável de membro que pode usar.

É uma opção perfeitamente viável. Todos os idiomas modernos têm um recurso que pode ser usado para se referir a outro idioma.

DeadMG
fonte
1

Existe uma abordagem semelhante com ligeira variação, mas que oferece vantagens:

Digamos que o pai A contenha o componente C.

No componente C, declare InterfaceC e mantenha referência a ele. Essa é a interface do componente com o mundo exterior.

O pai A implementa a InterfaceC e define sua referência no componente C. O componente C vê o pai A como InterfaceC.

A idéia é: Um componente fala para o exterior usando sua interface.

As vantagens de usar isso ao definir o pai diretamente é:

Digamos que o componente faça alguma coisa e precise notificar o pai. Chama a interface. Mais tarde, você decide que deseja alterar o pai. O componente não se importa e você não fará nenhuma alteração.

Diga depois que você deseja notificar muitos objetos de um evento. Você simplesmente cria uma lista de InterfaceC e adiciona referências a ela.

Desvantagens: Uma classe pai acabará implementando muitas interfaces (embora eu pense nisso como uma vantagem, pois, olhando a declaração de classe, eu imediatamente sei quem fala com ela)

Makketronix
fonte
0

Observe que isso é específico do c #. Não sei se c ++ tem algo semelhante.

Se você possui um gui-form com botões de pressão, geralmente usa uma abordagem diferente usando Event-Subscription, também conhecido como Observer_pattern ou Publish-subscribe pattern .

O botão normalmente não conhece a forma específica em que vive. Em vez disso, o botão aciona ou publica um evento e o formulário recebe uma notificação assinada e pode reagir de acordo.

Além dos gui-s, esse mecanismo pode ser usado em todas as relações paren-filho

k3b
fonte