Digamos que eu tenho uma classe Enemy, e o construtor seria algo como:
public Enemy(String name, float width, float height, Vector2 position,
float speed, int maxHp, int attackDamage, int defense... etc.){}
Isso parece ruim porque o construtor tem muitos parâmetros, mas quando eu crio uma instância Enemy, preciso especificar todas essas coisas. Também quero esses atributos na classe Enemy, para que eu possa percorrer uma lista deles e obter / definir esses parâmetros. Eu estava pensando em talvez subclassificar o Inimigo no EnemyB, EnemyA, enquanto codificava seu maxHp e outros atributos específicos, mas então eu perderia o acesso aos seus atributos codificados se quisesse percorrer uma lista de Enemy (consistindo em EnemyA, EnemyB e Do InemyC).
Eu só estou tentando aprender a codificar de forma limpa. Se isso faz diferença, eu trabalho em Java / C ++ / C #. Qualquer ponto na direção certa é apreciado.
Respostas:
A solução é agrupar os parâmetros em tipos compostos. Largura e Altura estão conceitualmente relacionados - eles especificam as dimensões do inimigo e geralmente serão necessários juntos. Eles podem ser substituídos por um
Dimensions
tipo, ou talvez umRectangle
tipo que também inclua a posição. Por outro lado, pode fazer mais sentido agruparposition
e formarspeed
umMovementData
tipo, especialmente se a aceleração mais tarde entrar em cena. A partir do contexto eu assumomaxHp
,attackDamage
,defense
, etc também pertencem juntos em umStats
tipo. Portanto, uma assinatura revisada pode ser algo como isto:Os detalhes de onde desenhar as linhas dependerão do restante do seu código e de quais dados são comumente usados juntos.
fonte
Enemy
é apenas a classe que tem como alvo oPlayer
, mas sua classe base comumCombatant
precisa das estatísticas de luta.Dimensions
/MovementData
como simples contêineres de dados antigos) ou métodos (se ele as transformar em dados abstratos tipos / objetos). Como exemplo, se ele ainda não tivesse criado umVector2
tipo, ele poderia ter acabado fazendo matemática vetorialEnemy
.Você pode dar uma olhada no padrão Builder . No link (com exemplos do padrão versus alternativas):
fonte
Usar subclasses para predefinir alguns valores não é desejável. Apenas subclasse quando um novo tipo de inimigo tem comportamento diferente ou novos atributos.
O padrão de fábrica geralmente é usado para abstrair sobre a classe exata usada, mas também pode ser usado para fornecer modelos para a criação de objetos:
fonte
Eu reservaria a subclassificação para classes que representam objetos que você pode usar independentemente, por exemplo, classe de caracteres em que todos os caracteres, não apenas os inimigos, têm nome, velocidade, maxHp ou uma classe para representar sprites que estão presentes na tela com largura, altura, posição.
Não vejo nada inerentemente errado com um construtor com muitos parâmetros de entrada, mas se você quiser dividi-lo um pouco, pode haver um construtor que configure a maioria dos parâmetros e outro construtor (sobrecarregado) que pode ser usado para definir os específicos e definir outros com os valores padrão.
Dependendo do idioma que você optar por usar, alguns podem definir valores padrão para os parâmetros de entrada do seu construtor, como:
fonte
Um exemplo de código a ser adicionado à resposta de Rory Hunter (em Java):
Agora, você pode criar novas instâncias do Enemy como esta:
fonte