Como projetar um padrão composto em Python?

5

O conceito

Estou programando uma interface sobre o pygame como um projeto pessoal, para facilitar a criação de jogos para mim.

Até agora eu consegui projetar uma arquitetura que se comporta assim:

  • Objetos são componentes exibíveis que podem aparecer e se mover na tela
  • Objetos podem ter objetos filhos
  • Quando um objeto é exibido, ele pede a todos os filhos que se exibam na superfície dos pais.
  • Os objetos têm três elementos importantes: um sistema de retorno de chamada, um sistema gráfico e um sistema físico para agir, exibir e mover respectivamente.

Então, quando eu quero criar uma "cena" de jogo, eu crio um objeto "raiz" que contém outros objetos como o jogador, o mouse, o chão, monstros ...

Então eu só tenho que pedir para a raiz se exibir, e todo objeto aparece recursivamente.

Eu projetei isso sem saber sobre o padrão composto no início, apenas o básico da OOP.

Minha principal questão era tornar a propriedade de substitutibilidade de objetos que vem da herança funcionar bem com a composição recursiva que fiz.

Quero dizer que tenho uma classe "abstrata" chamada "Objeto" (coloquei o resumo em aspas porque o Python realmente não tem esse conceito) que é herdada por classes como "Imagem" (para poder exibir) ou "MovingObject" (para poder mover). Aqui, a herança serve para estender minhas habilidades com objetos.

Mas meu padrão composto exige que "grupos de objetos sejam considerados iguais a objetos únicos".

Então, quando eu chamo recursivamente um método de um objeto, ele chama esse método de cada filho do objeto, independentemente do fato de que alguns deles podem não ter esse método.

Exemplo

Por exemplo, vamos usar esse elemento raiz:

  • root (imagem)
    • player (MovingObject)
    • cloud (MovingObject)
    • plano de fundo (imagem)
    • sol (imagem)

Agora vamos supor que queremos chamar o método move() no elemento raiz, para fazer com que cada filho seja movido: Primeiro, não podemos porque root é uma instância de Imagem, portanto, ele não conhece o método move() . Mas mesmo se fosse o caso, as crianças "background" e "sun" não saberiam disso.

Então eu decidi colocar um método vazio move() dentro da minha classe de objeto "abstract", então todo objeto sabe disso, mesmo que não faça nada.

A questão é que minha classe Object agora contém métodos vazios que não entende nem precisa, apenas para permitir o comportamento recursivo.

Solução possível

Então eu ouvi sobre toda a confusão de "herança versus composição" e uma das soluções que me veio à mente foi parar de usar a herança para habilidades de objetos e usar a composição. Isso significa que eu criaria, por exemplo, uma classe "Body", uma classe "Image" e uma classe "Callback" que representariam ações diferentes, e então as encaixaria em uma instância de Object para "equipá-lo" e dar mais poder a ele. .

Mas então eu pensei que isso dificilmente mudaria alguma coisa porque eu teria que chamar move() , e então o objeto verificaria se ele tinha o plug-in do Body e o usaria. Mas ainda requer que o método move() esteja presente dentro da classe Object.

Perguntas

Então, estou me voltando para vocês para me dar conselhos sobre meu padrão:

  • Eu entendi bem como o padrão composto funciona?
  • A minha abordagem está correta?
  • O uso de aulas de "plug-in" me ajudará?
  • O comportamento recursivo é uma boa ideia?
  • Existem outros padrões mais adequados às minhas necessidades?

Espero que você possa me dar algumas dicas!

    
por Jérôme 11.07.2013 / 12:44
fonte

1 resposta

2

Em um objeto de design limpo em uma determinada árvore deve ser usado com uma interface uniforme. Suas dúvidas refletem um cheiro de design.

O objetivo de ter árvores de objeto em cenas é poder aplicar transformações geométricas a um grupo de objetos. Então, se você tem objetos que não podem se mover, eles não pertencem à árvore. Não faz sentido.

Aqui está uma solução possível. Você pode ter uma classe de renderização que pode ter objetos de plano de fundo e a raiz dos objetos móveis. Todos os objetos móveis podem se mover. Uma transformação aplicada a um objeto é propagada para seus filhos.

Para renderizar a cena, você deve renderizar os objetos de plano de fundo que não podem ser movidos e a cena real chamando uma função de renderização na raiz.

    
por 16.07.2013 / 10:09
fonte