Resumo : neste tutorial, você aprenderá sobre o padrão de design do método de fábrica C# e como usá-lo para criar objetos sem acoplar fortemente o código de criação do objeto ao código do cliente.
Introdução ao padrão de design do método de fábrica C#
Uma fábrica do mundo real produz produtos. Na programação, uma fábrica cria objetos. Quando um método cria e retorna um objeto, ele é chamado de método de fábrica.
O padrão Factory Method é um padrão de design criacional, que fornece uma interface para criar objetos em uma superclasse, mas permite que as subclasses decidam o tipo de objeto.
O diagrama UML a seguir ilustra o padrão Factory Method:
O padrão Factory Method consiste nos seguintes participantes:
Creator
: a classe abstrata que define um método de fábrica para criar objetos. Podecreator
ser uma interface se não tiver uma implementação compartilhada com as subclasses.Product
: a classe abstrata que define a interface para os objetos criados pelo método de fábrica. Assim como oCreator
, oProduct
pode ser uma interface.ConcreteFactory
: a classe concreta que herda daCreator
classe. AConcreteFactory
classe criaConcreateProduct
que herda doProduct
.ConcreteProduct
: a classe concreta que estende aProduct
classe.
Aqui está a implementação do padrão de método de fábrica em C#:
namespace FactoryMethod;
public abstract class Product {}
public abstract class Creator
{
public abstract Product FactoryMethod();
public void Operation()
{
var product = FactoryMethod();
// process the product
// ...
Console.WriteLine($"Work with the {product}");
}
}
public class ConcreateProduct: Product {}
public class ConcreteFactory : Creator
{
public override Product FactoryMethod() => new ConcreateProduct();
}
public class Program
{
public static void Main(string[] args)
{
var creator = new ConcreteCreator();
creator.Operation();
}
}
Linguagem de código: C# ( cs )
Saída:
Work with the FactoryMethod.ConcreateProduct
Linguagem de código: JavaScript ( javascript )
Padrão de método de fábrica versus a nova palavra-chave
1) A palavra-chave new cria dependências entre o código do cliente e as implementações concretas das classes
Ao usar a new
palavra-chave para criar objetos de classes, você cria dependências entre o código do cliente e a implementação concreta das classes.
Se as classes mudarem, você deverá alterar o código do cliente para acomodar a nova implementação. Isso torna seu código fortemente acoplado e difícil de estender.
O padrão Factory Method separa o código do cliente da implementação dos objetos que estão sendo criados.
O código do cliente só precisa conhecer a interface de fábrica, que fornece uma maneira de criar objetos sem conhecer a implementação específica dos objetos que cria.
Portanto, o método de fábrica torna seu código mais flexível, testável e mais fácil de estender.
2) A nova palavra-chave dificulta a troca de implementações
A new
palavra-chave também dificulta a troca de implementações. Se você introduziu uma nova implementação ou substituiu uma existente, será necessário atualizar o código do cliente. Isto viola o princípio aberto-fechado .
Por outro lado, usar o Factory Method facilita a troca de implementações sem a necessidade de modificar o código do cliente.
A razão é que o código do cliente só precisa conhecer a interface de fábrica e pode utilizá-la para criar objetos sem conhecer a implementação específica que está sendo utilizada.
Exemplo de padrão de design do método de fábrica C#
O programa a seguir demonstra como usar o padrão Factory Method para implementar uma política de descontos para um sistema de pedidos simplificado:
namespace FactoryMethod;
public abstract class Discount
{
public abstract decimal GetPercentage();
}
public class RegularDiscount : Discount
{
public override decimal GetPercentage() => 0.1m;
}
public class IrregularDiscount : Discount
{
public override decimal GetPercentage() => 0.15m;
}
public abstract class DiscountPolicy
{
public abstract Discount Create();
public decimal Apply(decimal Price)
{
var discount = Create();
return Price * (1 - discount.GetPercentage());
}
}
public class RegularDiscountPolicy : DiscountPolicy
{
public override Discount Create() => new RegularDiscount();
}
public class IrregularDiscountPolicy : DiscountPolicy
{
public override Discount Create() => new IrregularDiscount();
}
public class Order
{
private readonly decimal _netAmount;
public decimal Amount => OrderDiscountPolicy.Apply(_netAmount);
public DiscountPolicy OrderDiscountPolicy
{
get; private set;
}
public Order(decimal amount, DiscountPolicy discountPolicy)
{
_netAmount = amount;
OrderDiscountPolicy = discountPolicy;
}
}
public class Program
{
public static void Main()
{
var order = new Order(1000, new IrregularDiscountPolicy());
Console.WriteLine(order.Amount);
}
}
Linguagem de código: C# ( cs )
Saída:
850.00
Linguagem de código: CSS ( css )
Como funciona.
O diagrama UML a seguir ilustra como funcionam os relacionamentos entre as classes no programa:
Primeiro, defina DiscountPolicy como uma classe abstrata. A classe DiscountPolicy possui o método Create() que cria e retorna um novo objeto Discount.
A seguir, defina as classes RegularDiscountPolicy
e IrregularDiscountPolicy
que estendem a DiscountPolicy
classe. O Create()
método dessas classes retorna a RegularDiscount
e IrregularDiscount
object, respectivamente.
Em seguida, defina a Discount
classe como uma classe abstrata. A Discount
classe tem duas classes concretas, incluindo classes RegularDiscount
e IrregularDiscount
.
Depois disso, defina a Order
classe que utiliza a DiscountPolicy
classe. A Order
classe armazena um valor líquido do pedido e uma política de desconto. A Amount
propriedade devolve o valor após aplicar a política de desconto ao valor líquido.
Por fim, crie um Order
objeto com valor líquido 1000
e um IrregularDiscountPolicy
objeto no Main()
método da Program
classe e exiba o valor após aplicar a política de desconto no console.
Neste exemplo, você pode trocar a política de desconto de para IrregularDiscountPolicy
sem RegularDiscountPolicy
modificar a Order
classe.
Além disso, você pode introduzir uma nova política de descontos, por exemplo, SpecialDiscountPolicy
e trocá-la pela política de descontos atual sem alterar a Order
classe.
Resumo
- Use o padrão de design Factory Method para criar objetos sem acoplar fortemente o código de criação do objeto ao código do cliente.