Existem padrões de design conhecidos para implementar modelos de desconto?
Por modelos de desconto, quero dizer o seguinte:
Se um cliente compra o Produto X, o Produto Y e o Produto Z, recebe um desconto de 10% ou US $ 100.
Se um cliente compra 100 unidades do Produto X, recebe um desconto de 15% ou US $ 500
Se um cliente trouxe no último ano mais de US $ 100 mil, ele recebe um desconto fixo de 20%
Se um cliente comprou 2 unidades do Produto X, ele recebe 1 unidade do Produto X (ou Produto Y) gratuitamente.
...
Existe um padrão genérico que pode ser aplicado para lidar com todos os cenários acima? Estou pensando em alguns modelos, mas incapaz de encontrar um genérico.
design
design-patterns
financial
Kanini
fonte
fonte
Respostas:
Se o problema for a necessidade de aplicar vários descontos, em determinadas circunstâncias, convém considerar o padrão da Cadeia de Responsabilidade .
Em poucas palavras, você passa as informações que deseja processar para o primeiro processador e decide a partir daí se as repassa para outros processadores antes de retornar o resultado.
Dessa forma, você pode alterar a estrutura e a sequência dos processadores sem alterar o código de chamada.
fonte
Os padrões de estratégia, decorador e estado se destacam para mim como possíveis pontos de partida. O estado pode ser particularmente útil para 2 ou 3, pois 2 depende do estado do pedido e 3 depende do estado do cliente dentro de um período de tempo. O Strategy e o Decorator se destacam dos demais, pois você pode usar a estratégia para implementar vários algoritmos de cálculo de preço do pedido e o decorador para adicionar novos descontos ao pedido.
No entanto, lembre-se de que os padrões de design são apenas modelos. Pode não haver um único padrão que se aplique, mas sim um sistema de padrões. Considere também fazer modificações nos modelos descritos para ajustá-los melhor à sua solução. É melhor ter um bom design do que forçar um padrão em que não necessariamente ajude apenas por poder dizer que você tem um padrão.
fonte
Bem, eu projetaria um modelo de desconto como um par "Pré-condição" e "Desconto", em que "Pré-condição" é uma classe com métodos
ou e
e Discount tem um método
void ApplyTo(Customer c)
. Isso permite combinar qualquer tipo de pré-condição com qualquer tipo de desconto (acho que essa é uma forma de "padrão de ponte").Se você tiver um número fixo de pré-condições, poderá resolver o problema criando subtipos específicos (padrão de estratégia). No entanto, quando é permitido que suas pré-condições sejam muito complexas, com instruções lógicas como AND, OR e NOT, você pode implementar melhor algum tipo de interpretador de regras para as condições. As regras podem ser uma sequência de texto simples escrita em um "idioma específico do domínio" simples.
O mesmo vale para a classe "Desconto", você pode ter alguns subtipos para diferentes tipos de descontos ou uma abordagem geral em que as regras de desconto são fornecidas em forma de texto, avaliadas por algum intérprete.
fonte
Provavelmente, precisamos de uma interface IDiscount, pois todos os descontos diferentes são a mesma coisa, e queremos lidar com eles conceitualmente como descontos genéricos.
A classe "pedido deste cliente" provavelmente precisa de uma coleção de descontos. Lista? Jogo da velha? Lista vinculada? Não se importe ainda. Aplicam-se descontos à compra, não ao cliente!
Mantenha a criação da instância de desconto separada do cliente, carrinho de compras, histórico etc. Isso mudará muito - como apontou @jfrankcarr.
Provavelmente, uma classe diferente para cada desconto, pois o algoritmo e os parâmetros para cada desconto variam muito e de forma imprevisível.
Vejo muita manipulação de eventos, pois o cálculo do desconto responde a alterações no carrinho de compras e vice-versa.
Aplicação de padrão de design
strategy pattern
. IDiscount é a interface para implementar diferentes algoritmos de desconto.Eu vejo um
factory
. Certamente não é umaabstract factory pattern
aula completa , mas uma única classe neste momento da análise. Razoavelmente, deve haver um único local em que haja contexto suficiente para decidir quais descontos se aplicam e depois criá-los. Uma classe. Se as regras para a aplicação de descontos explodirem posteriormente devido a uma grande proliferação do Departamento de Marketing, qualquer lógica adicional de Construção de descontos ainda deverá se fundir nessa classe básica de fábrica, eu acho.Eu posso ver
Chain of Responsibility
. Isso não é mutuamente exclusivo dafactory
ideia. Em vez de iterar uma coleção de descontos, cada desconto chama a próxima pessoa. A classe "pedido do cliente" não possui uma coleção de descontos nesse caso.O fator "hmmmm ...." na Cadeia de Responsabilidade, eu acho, é que cada Desconto tem uma referência ao próximo. A implicação é que a ordem é importante. O que não é o caso. Além disso, o conceito que o CR incorpora é que um objeto não pode atender à solicitação e, portanto, é passado "até a próxima autoridade superior". Nosso modelo é diferente. A única solicitação é calcular. Todo desconto faz isso. A saída ou efeito pode ser nulo, mas todo desconto é calculado. Eu instintivamente me inclino a uma maior fidelidade do mundo real.
Suposições
O que muda, o que permanece o mesmo?
Os descontos são muito diferentes. Número e tipo de parâmetros diferentes para compor cada regra.
Os argumentos para descontos qualificados são alterados conforme o carrinho de compras.
O número de descontos disponíveis muda
Os descontos que esse cliente qualifica para alterações à medida que seu carrinho de compras muda.
O histórico de compras não muda no contexto desta compra
O custo total é alterado dinamicamente em função das linhas de compra e dos descontos aplicados.
Após a aplicação inicial, a produção de um desconto pode mudar, como a quantidade da compra, por exemplo.
fonte
Logicamente, um modelo de desconto pode ser qualquer coisa , então você não pode presumir que pode programar todos os casos com antecedência. Nem alguém que responde à sua pergunta pode ter certeza absoluta do que realmente precisa. No entanto, supondo que você obtenha os tipos usuais de descontos encontrados no mundo real ...
Uma grande questão é se os descontos serão programados ou se você deseja que os usuários os inscrevam. Como mencionado acima, você nunca pode programá-los, mas geralmente o objetivo é tentar torná-lo mais como os casos comuns, em vez de programá-los todos. Isso se aplica até certo ponto, mesmo se os programadores forem usados para criar todos os descontos.
Martin Fowler menciona "Método de instância individual" em "Padrões de análise: modelos de objetos reutilizáveis" como parte de como implementar "Regras de postagem" para sistemas de contabilidade, mas as regras parecem bastante semelhantes às suas. Eu daria mais detalhes, mas é um trabalho protegido por direitos autorais e
Para uma interface com o usuário, você precisa criar casos de uso bastante simples ou criar um interpretador e um construtor de consultas. Possivelmente ambos, um para casos simples e outro mais avançado. Se você escreve um intérprete, esse é provavelmente um bom argumento para usar o padrão Interpreter, pois é relativamente simples de codificar em comparação com um gerador de analisador, e o tempo de análise mais lento provavelmente não importa. (Se você gosta de usar geradores de analisador, não me deixe pará-lo).
Não tente fazer tudo com um intérprete - em algum momento você está apenas programando em sua própria linguagem ruim, para que você possa usar uma linguagem real. Se a sua linguagem interpretada suportar funções (provavelmente deve suportar chamá-las - defini-las é duvidosa), elas podem ser codificadas em uma linguagem real. Não vá mais longe nesse caminho do que o necessário.
Não importa o que você faça, alguém desejará que o desconto se baseie em sua compra dentro de 30 dias úteis de uma promoção - onde os dias úteis contam apenas se não houver feriado na região definida pelo código postal da loja ou pelo cliente. Código postal. Portanto, não tente projetar o sistema perfeito com antecedência - suponha que às vezes seja necessário escrever código para novos tipos de descontos e projetá-lo adequadamente.
fonte
Existe algum motivo para perguntar se existe um padrão útil para isso? Que tipo de padrão é necessário - estrutural ou comportamental?
Idealmente, se eu escrevesse um software para isso, basta um algoritmo . Uma função simples que calcula o desconto total da seguinte maneira:
Você não precisa de nada além disso!
Para esclarecer: eu entendo que haverá muitas regras - a mais básica dessa representação deve estar na forma de uma base de regra (conjunto de atributos de dados e desconto resultante) e a função como a acima iteraria para computá-la. Se as regras forem adicionadas ou removidas, você não deverá alterar o código - basta alterar a base de regras.
O padrão será necessário apenas se precisarmos que objetos diferentes precisem acessar APIs um do outro ou se comunicar para implementar uma tarefa.
PS: Pense nisso - quando o firewall processa pacotes e passa ou rejeita pacotes (ou modifica) - que padrão de design ele usa? A resposta é NENHUMA das opções acima descritas!
fonte