A lógica condicional deve sempre ser codificada via sistema de tipos sempre que possível?

4

Eu tenho uma escolha.

Opção 1:

public class Sample
{
    bool IsRelevant { get; set; }
}

Opção 2:

public class Sample
{
}

public class RelevantSample : Sample
{
}

Existe uma regra clara e bem conhecida sobre como tomar essa decisão?

Minha pesquisa: Eu já ouvi falar sobre a refatoração "Substituir condicional por polimorfismo" antes, mas geralmente lida com grandes comandos de troca:

link

link

link

Existe uma questão um pouco relacionada que descreve uma situação diferente (flag como um argumento de método em vez de parte de uma entidade de domínio):

é errado usar um parâmetro booleano para determinar o comportamento?     
por Den 30.11.2015 / 23:39
fonte

3 respostas

8

Eu acho que a escolha da língua é irrelevante. O que é importante para tomar a decisão é como a informação é usada.

Se Sample s se comportar de maneira diferente, dependendo do valor de isRelevent , então faz sentido dividi-lo em três (não duas) classes. A base Sample class, a RelevantSample class e a IrrelevantSample class. Todos os objetos de amostra seriam instanciados de uma das duas classes posteriores (seguindo assim a heurística de que as classes base deveriam ser abstratas). Outros objetos podem informar objetos de amostra de eventos sem se preocupar se a amostra é relevante ou não.

No entanto, se for mais uma questão de outros objetos se comportarem de maneira diferente, dependendo da relevância da amostra, você desejará usar a opção 1 e tornar isRelevant um campo que possa ser consultado.

    
por 01.12.2015 / 00:24
fonte
11

Você já tem duas boas respostas; uma terceira razão para manter a propriedade é que o padrão que você está descrevendo é um padrão de "um tiro". Tudo fica em forma de pêra quando você adiciona um segundo booleano. Nós começamos com:

public class Sample
{
    public bool IsRelevant { get; protected set; }
}

e refatorizamos isso em:

public abstract class Sample {}
public class RelevantSample : Sample {}
public class IrrelevantSample : Sample {}

E agora percebemos, oh, espere, as amostras também podem ser frenéticas ou antifrônicas:

public abstract class Sample 
{
    public bool IsFrobby { get; protected set; }
}
public class RelevantSample : Sample {}
public class IrrelevantSample : Sample {}

E agora, como podemos mover isso para o sistema de tipos?

public class RelevantFrobbySample : RelevantSample {}
public class RelevantAntifrobbySample : RelevantSample {}
public class IrrelevantFrobbySample : IrrelevantSample {}
public class IrrelevantAntifrobbySample : IrrelevantSample {}

E agora quero criar um método que use apenas amostras de fragmentos. Como faço isso?

As linguagens de herança única exigem que você escolha seu "pivot de herança" com muito cuidado porque só obtém uma chance.

    
por 15.12.2015 / 17:10
fonte
3

Não em c #.

A codificação de comportamento implícito em tipos é má em linguagem C # e similares, porque a única maneira de obter informações do tipo é if x is T tipos de verificações (ou truques com dynamic ou reflexão). Portanto, qualquer alteração (adicionar uma nova variante, alterar o comportamento de um tipo) significa que você entra em todos os seus consumidores, violando o Princípio do Fechado Aberto.

    
por 30.11.2015 / 23:48
fonte