Decisão de design de classe
-
09-06-2019 - |
Pergunta
Estou com um pequeno dilema que talvez você possa me ajudar a resolver.
Estive trabalhando hoje na modificação da associação do ASP.NET para adicionar um nível de indireção.Basicamente, a associação do ASP.NET oferece suporte a usuários e funções, deixando todas as regras de autorização baseadas no fato de um usuário pertencer a uma função ou não.
O que preciso fazer é adicionar o conceito de Função, onde um usuário pertencerá a uma função (ou funções) e a função terá uma ou mais funções associadas a ela, permitindo-nos autorizar uma ação específica com base na pertença do usuário. para uma função que tem uma função atribuída.
Dito isto, meu problema não tem nada a ver com isso, é uma questão genérica de design de classe.
Quero fornecer um método abstrato em minha classe RoleProvider base para criar a função (e persisti-la), mas quero torná-lo opcional para salvar uma descrição para essa função, então preciso criar meu método CreateFunction com uma sobrecarga, um assinatura aceitando o nome e a outra aceitando o nome e a descrição.
Posso pensar nos seguintes cenários:
Crie ambas as assinaturas com o modificador abstrato.Isso tem o problema de o implementador poder não respeitar a melhor prática que diz que uma sobrecarga deve chamar a outra com os parâmetros normalizados, e a lógica deve ficar apenas na final (aquela com todos os parâmetros).Além disso, não é legal exigir que ambos os métodos sejam implementados pelo desenvolvedor.
Crie o primeiro como virtual e o segundo como abstrato.Chame o segundo do primeiro e permita que o implementador substitua o comportamento.Tem o mesmo problema: o implementador pode tomar "decisões erradas" ao substituí-lo.
O mesmo que antes, mas não permita que o primeiro seja substituído (remova o modificador virtual).O problema aqui é que o implementador precisa estar ciente de que o método pode ser chamado com uma descrição nula e precisa lidar com essa situação.
Acho que a melhor opção é a terceira...
Como esse cenário é tratado em geral?Quando você projeta uma classe abstrata e ela contém métodos sobrecarregados.Não é tão incomum, eu acho...
Solução
Acho que a melhor combinação de SECAGEM e forçar o contrato é a seguinte (em pseudocódigo):
class Base {
public final constructor(name) {
constructor(name, null)
end
public abstract constructor(name, description);
}
ou alternativamente:
class Base {
public abstract constructor(name);
public final constructor(name, description) {
constructor(name)
this.set_description(description)
}
private final set_description(description) {
...
}
}
Existe uma regra em Java que suporta esta decisão:"nunca chame métodos não finais de um construtor."
Outras dicas
Para responder a primeira parte do seu post, dê uma olhada no AzMan (Gerenciador de Autorização), que, aliás, está embutido no Windows.Tem a capacidade de especificar operações que podem ser recombinadas em funções ou atribuídas diretamente aos usuários.
Para responder à segunda parte da sua pergunta, eu não usaria uma classe Abstract.Em vez disso, apenas forneça a funcionalidade no construtor e pronto.Parece que você deseja o comportamento especificado e não deseja que ele mude.Por que forçar os descendentes a fornecer a implementação.