Em esta série de posts , Eric Lippert descreve um problema no design orientado a objetos usando assistentes e guerreiros como exemplos, em que:
abstract class Weapon { }
sealed class Staff : Weapon { }
sealed class Sword : Weapon { }
abstract class Player
{
public Weapon Weapon { get; set; }
}
sealed class Wizard : Player { }
sealed class Warrior : Player { }
e depois adiciona algumas regras:
- Um guerreiro só pode usar uma espada.
- Um assistente pode usar apenas uma equipe.
Ele então demonstra os problemas com os quais você se depara se tentar aplicar essas regras usando o sistema do tipo C # (por exemplo, responsabilizando a Wizardclasse por garantir que um assistente possa usar apenas uma equipe). Você viola o princípio de substituição de Liskov, corre o risco de exceções em tempo de execução ou acaba com um código difícil de estender.
A solução que ele apresenta é que nenhuma validação é feita pela classe Player. É usado apenas para rastrear o estado. Então, em vez de dar uma arma a um jogador:
player.Weapon = new Sword();
o estado é modificado por se de Commandacordo com Rules:
... criamos um
Commandobjeto chamadoWieldque leva dois objetos de estado do jogo, aPlayere aWeapon. Quando o usuário emite um comando para o sistema “esse assistente deve usar essa espada”, esse comando é avaliado no contexto de um conjunto deRules, que produz uma sequência deEffects. Temos umaRuleque diz que quando um jogador tenta empunhar uma arma, o efeito é que a arma existente, se houver, é descartada e a nova arma se torna a arma do jogador. Temos outra regra que fortalece a primeira regra, que diz que os efeitos da primeira regra não se aplicam quando um mago tenta empunhar uma espada.
Eu gosto dessa idéia em princípio, mas tenho uma preocupação sobre como ela pode ser usada na prática.
Nada parece impedir que um desenvolvedor de iludirem o Commandse Ruleé simplesmente definindo o Weaponem um Player. A Weaponpropriedade precisa estar acessível pelo Wieldcomando, portanto, não pode ser feita private set.
Então, o que impede um desenvolvedor de fazer isso? Eles apenas precisam se lembrar de não?