Codificação não é tão difícil, na verdade . A parte difícil é escrever um código que faça sentido, seja legível e compreensível. Então, eu quero ter um desenvolvedor melhor e criar uma arquitetura sólida.
Então, eu quero criar uma arquitetura para NPCs em um videogame. É um jogo de estratégia em tempo real como Starcraft, Age of Empires, Command & Conquers, etc. etc. Portanto, terei diferentes tipos de NPCs. Um NPC pode ter um para muitas habilidades (métodos) destes: Build()
, Farm()
e Attack()
.
Exemplos:
Trabalhador pode Build()
e Farm()
Guerreiro pode Attack()
Cidadão podem Build()
, Farm()
e Attack()
Fisherman pode Farm()
eAttack()
Espero que tudo esteja claro até agora.
Então agora eu tenho meus tipos de NPCs e suas habilidades. Mas vamos ao aspecto técnico / programático.
Qual seria uma boa arquitetura programática para meus diferentes tipos de NPCs?
Ok, eu poderia ter uma classe base. Na verdade, acho que essa é uma boa maneira de manter o princípio DRY . Para que eu possa ter métodos como WalkTo(x,y)
na minha classe base, já que todo NPC poderá se mover. Mas agora vamos ao verdadeiro problema. Onde eu implemento minhas habilidades? (lembre-se: Build()
, Farm()
e Attack()
)
Como as habilidades consistirão na mesma lógica, seria irritante / violar o princípio DRY implementá-las para cada NPC (Worker, Warrior, ..).
Ok, eu poderia implementar as habilidades dentro da classe base. Isso exigiria algum tipo de lógica que verifica se um NPC pode usar a habilidade X. IsBuilder
, CanBuild
, .. Eu acho que é claro que eu quero expressar.
Mas não me sinto muito bem com essa ideia. Isso soa como uma classe base inchada com muita funcionalidade.
Eu uso c # como linguagem de programação. Portanto, herança múltipla não é uma opção aqui. Meios: Ter classes base extras como Fisherman : Farmer, Attacker
não vai funcionar.
fonte
Respostas:
A Herança de Composição e Interface são as alternativas usuais à herança múltipla clássica.
Tudo o que você descreveu acima que começa com a palavra "pode" é um recurso que pode ser representado com uma interface, como em
ICanBuild
, ouICanFarm
. Você pode herdar tantas dessas interfaces quanto achar necessário.Você pode passar objetos de construção e agricultura "genéricos" através do construtor de sua classe. É aí que entra a composição.
fonte
ICanBuild
. O fato de você também ter ferramentas para construção é uma preocupação secundária na hierarquia de objetos.Como outros pôsteres mencionaram, uma arquitetura de componentes pode ser a solução para esse problema.
Nesse caso, estenda a função de atualização para implementar qualquer funcionalidade que o NPC deva ter.
Iterar um contêiner de componente e atualizar cada componente permite que a funcionalidade específica de cada componente seja aplicada.
Como cada tipo de objeto é desejado, você pode usar alguma forma do padrão de fábrica para construir os tipos individuais desejados.
Eu sempre encontro problemas à medida que os componentes ficam cada vez mais complexos. Manter a complexidade do componente baixa (uma responsabilidade) pode ajudar a aliviar esse problema.
fonte
Se você definir interfaces como essa
ICanBuild
, seu sistema de jogo deve inspecionar todos os NPCs por tipo, o que normalmente é desaprovado no OOP. Por exemplo:if (npc is ICanBuild)
.Você está melhor com:
Então:
... ou, é claro, você pode usar várias arquiteturas diferentes, como algum tipo de linguagem específica de domínio na forma de uma interface fluente para definir diferentes tipos de NPCs, etc., onde você cria tipos de NPC combinando comportamentos diferentes:
O construtor NPC pode implementar um
DefaultWalkBehavior
que possa ser substituído no caso de um NPC que voe, mas não possa andar, etc.fonte
if(npc is ICanBuild)
eif(npc.CanBuild)
. Mesmo quando eu preferiria onpc.CanBuild
caminho da minha atitude atual.Eu colocaria todas as habilidades em classes separadas que herdam do Ability. Em seguida, na classe de tipo de unidade, tenha uma lista de habilidades e outras coisas, como ataque, defesa, vida máxima, etc.
Defina todos os tipos de unidades em um arquivo de configuração ou em um banco de dados, em vez de codificá-lo.
Então o designer de níveis pode ajustar facilmente as habilidades e estatísticas dos tipos de unidades sem recompilar o jogo, e também as pessoas podem escrever mods para o jogo.
fonte