C#
- O padrão Humble Object
![]() |
Hoje vou apresentar o padrão Humble Object. (Humble Object Pattern) |
O Humble Object Pattern é um padrão de design de software que visa facilitar a testabilidade de componentes complexos. Ele ajuda a isolar a lógica de negócios de um componente dos detalhes de implementação que podem ser difíceis de testar, como dependências externas, serviços de infraestrutura ou APIs externas.
O padrão Humble Object envolve a criação de uma interface humilde (humble interface) que define a funcionalidade principal do componente. Essa interface define os métodos e propriedades que representam as principais operações do componente.
Em seguida, o componente é dividido em duas partes:
A ideia por trás do Humble Object Pattern é que a parte humilde do componente é mais fácil de testar, pois não possui dependências externas complexas. Os testes de unidade podem ser escritos facilmente para a parte humilde, sem a necessidade de lidar com configurações complexas ou interações com recursos externos.
Assim, quando criamos programas, eles geralmente precisam se
comunicar com outras partes do computador ou com o mundo externo, como um banco
de dados ou serviço de Internet. Mas quando queremos testar nossos programas
para garantir que funcionem corretamente, pode ser difícil conversar com essas
outras partes.
Para resolver esse problema, podemos usar o Humble Object
Pattern para separar as partes do nosso programa que precisam se
comunicar com outras partes do computador ou com o mundo exterior das partes do
programa que não precisam. As partes do programa que não precisam falar com o
mundo exterior são muito mais fáceis de testar porque podemos testá-las
isoladamente sem nos preocuparmos com outras coisas.
No C#, você pode implementar o Humble Object Pattern utilizando
interfaces para definir a interface humilde e separar a lógica de negócios dos
detalhes de implementação. A injeção de dependência é frequentemente usada para
fornecer as dependências externas para o objeto humilde.
A seguir vamos dar um exemplo para ilustrar o uso deste padrão.
Usando o padrão Humble Object
Imagine que você tenha um componente chamado
OrderProcessor
responsável por
processar os pedidos dos clientes. Esse componente precisa interagir com um
serviço externo de pagamento para autorizar os pagamentos dos pedidos.
Vamos criar um projeto console no VS 2022 usando o .NET 7.0 e criar 3 classes para definir o modelo de domínio (vamos usar uma abordagem simplificada):
1- Order
public
class
Order { public int OrderId { get; set; } public string CustomerName { get; set; } public List<Product> Products { get; set; } public Payment Payment { get; set; } public Order(int orderId, string customerName, List<Product> products, Payment payment) { OrderId = orderId; CustomerName = customerName; Products = products; Payment = payment; } } |
2- Product
public
class
Product { public int ProductId { get; set; } public string Name { get; set; } public decimal Price { get; set; } public Product(int productId, string name, decimal price) { ProductId = productId; Name = name; Price = price; } } |
3- Payment
public
class
Payment { public string PaymentMethod { get; set; } public decimal Amount { get; set; } public Payment(string paymentMethod, decimal amount) { PaymentMethod = paymentMethod; Amount = amount; } } |
Definindo o serviço externo de pagamento usando a interface IPaymentService:
public
interface
IPaymentService { void AuthorizePayment(Payment payment); void CapturePayment(Payment payment); } |
A implementação seria feita na classe PaymentService que não irei mostrar para simplificar o código.
Vamos aplicar o Humble Object Pattern nesse caso.
1- Definindo a interface humilde (Humble)
public
interface
IOrderProcessor { void ProcessOrder(Order order); } |
2- Implementando o objeto humilde
public
class
OrderProcessor :
IOrderProcessor { private readonly IPaymentService _paymentService; public OrderProcessor(IPaymentService paymentService) { _paymentService = paymentService; } public void ProcessOrder(Order order) { // Lógica de negócio para processar o pedido // Chama o serviço de pagamento para autorizar o pagamento _paymentService.AuthorizePayment(order.Payment); // Mais lógica de processamento do pedido } } |
No exemplo acima, o OrderProcessor
é o objeto humilde que implementa a interface
IOrderProcessor
. Ele possui uma dependência no
IPaymentService
, que representa o
serviço externo de pagamento.
Implementando o suporte do objeto:
public
class
PaymentService :
IPaymentService { public void AuthorizePayment(Payment payment) { throw new NotImplementedException(); } public void CapturePayment(Payment payment) { throw new NotImplementedException(); } } |
O PaymentService
representa a
implementação do serviço de pagamento externo. Ele lida com as interações reais
com o serviço de pagamento.
Usando o Humble Object Pattern:
|
No código acima, você registra as implementações das interfaces
IOrderProcessor
e IPaymentService
na configuração da injeção de dependência do ASP.NET Core. Dessa forma, sempre
que um componente precisar do IOrderProcessor
ou do IPaymentService
, o framework fornecerá as instâncias
corretas.
Ao utilizar o Humble Object Pattern nesse exemplo, você pode testar o
OrderProcessor
facilmente, isolando-o
das interações com o serviço de pagamento externo. Nos testes de unidade, você
pode fornecer uma implementação simulada ou um mock do
IPaymentService
para verificar o comportamento do
OrderProcessor
sem depender de recursos externos ou interações complexas.
Essa abordagem torna os testes de unidade mais simples, mais rápidos e mais
confiáveis, pois se concentram apenas na lógica de negócio do
OrderProcessor
, sem se preocupar com o
serviço de pagamento real.
Ao mesmo tempo, a implementação real do
PaymentService
pode ser testada em níveis de teste mais
abrangentes, como testes de integração ou testes de sistema, garantindo que as
interações com o serviço de pagamento funcionem corretamente.
Essa separação entre o objeto humilde e o suporte do objeto ajuda a manter um código mais organizado, modular e de fácil manutenção. Além disso, o Humble Object Pattern facilita a implementação de testes automatizados e aumenta a testabilidade do seu código.
E estamos conversados.
"Jesus dizia, pois, aos judeus que criam nele: Se
vós permanecerdes na minha palavra, verdadeiramente sereis meus discípulos; E
conhecereis a verdade, e a verdade vos libertará."
João 8:31-32
Referências: