In an earlier article, I wrote about reducing Controller dependencies with generic factories. One criticism of this approach, which I agree with, is that it hides those dependencies. It uses service location, a well-known anti-pattern. I had reasoned that some service location was acceptable in this instance. I wasn't injecting the container around everywhere. I was using the container in one place, to resolve the specific factories that I needed. This was to avoid injecting many generic factories into a single controller. Instead, I would inject in a non-generic factory. I would then use the service locator pattern to call the correct factory. I've thought about this a bit more since. A better approach would be to group the factories together somehow. In this article, I’d like to discuss my approach to doing that. The façade pattern.
The Theory
So what’s the façade pattern all about? Well, it’s a way of grouping classes together. It provides a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use. This means we can group dependencies together behind a façade. We then inject the façade into the Controller. This reduces the number of interfaces we need to worry about.
That’s the theory out of the way. Let’s see some code!
A Practical Example
Let’s start by looking at an example Controller. Our ProductController
has GET
and POST
methods for adding products, amongst others. It uses a factory to create the ViewModel
for the GET
operation. The POST
operation accepts a command and uses a handler to process that command. It also displays a success or failure message in the view via a notifier. If you missed the articles on using commands/handlers or the notifier, you can read those here:
Now, back to the controller. Here's what it looks like before we introduce the façade:
public class ProductController : Controller
{
private readonly IViewModelFactory<ProductAddViewModel> productAddViewModelFactory;
private readonly ICommandHandler<ProductAddCommand, int> productAddCommandHandler;
private readonly INotifier notifier;
public ProductController(IViewModelFactory<ProductAddViewModel> productAddViewModelFactory,
ICommandHandler<ProductAddCommand, int> productAddCommandHandler,
INotifier notifier)
{
this.productAddViewModelFactory = productAddViewModelFactory;
this.productAddCommandHandler = productAddCommandHandler;
this.notifier = notifier;
}
public ActionResult Add()
{
var model = productAddViewModelFactory.Create();
return View(model);
}
[HttpPost]
public ActionResult Add(ProductAddCommand command)
{
if (!ModelState.IsValid)
{
var viewModel = productAddViewModelFactory.Create();
return View(viewModel);
}
var id = productAddCommandHandler.Execute(command);
if (id > 0)
{
notifier.Success("The product was added successfully.");
}
else
{
notifier.Error("There was an error adding the product. Please try again.");
}
return RedirectToAction("Add");
}
}
We're only looking at one operation here, but we now have 3 dependencies in the Controller
. If we keep following this pattern, we'll add a factory and handler for each subsequent operation. Just adding edit and delete, and we're up to 7. That's getting a bit busy. Let's introduce our façade and bring that number down again:
public interface IProductAddFacade
{
ProductAddViewModel GetProductAddViewModel();
int PostProductAddCommand(ProductAddCommand command);
void ShowMessage(int productId);
}
public class ProductAddFacade : IProductAddFacade
{
private readonly IViewModelFactory<ProductAddViewModel> productAddViewModelFactory;
private readonly ICommandHandler<ProductAddCommand, int> productAddCommandHandler;
private readonly INotifier notifier;
public ProductAddFacade(IViewModelFactory<ProductAddViewModel> productAddViewModelFactory,
ICommandHandler<ProductAddCommand, int> productAddCommandHandler,
INotifier notifier)
{
this.productAddViewModelFactory = productAddViewModelFactory;
this.productAddCommandHandler = productAddCommandHandler;
this.notifier = notifier;
}
public ProductAddViewModel GetProductAddViewModel()
{
return productAddViewModelFactory.Create();
}
public int PostProductAddCommand(ProductAddCommand command)
{
return productAddCommandHandler.Execute(command);
}
public void ShowMessage(int productId)
{
if (productId > 0)
{
notifier.Success("The product was added successfully.");
}
else
{
notifier.Error("There was an error adding the product. Please try again.");
}
}
}
We can now replace our 3 dependencies in the controller with a single façade dependency.
public class ProductController : Controller
{
private readonly IProductAddFacade productAddFacade;
public ProductController(IProductAddFacade productAddFacade)
{
this.productAddFacade = productAddFacade;
}
public ActionResult Add()
{
var model = productAddFacade.GetProductAddViewModel();
return View(model);
}
[HttpPost]
public ActionResult Add(ProductAddCommand command)
{
if (!ModelState.IsValid)
{
var viewModel = productAddFacade.GetProductAddViewModel();
return View(viewModel);
}
var id = productAddFacade.PostProductAddCommand(command);
productAddFacade.ShowMessage(id);
return RedirectToAction("Add");
}
}
We've simplified the Controller logic a little and reduced its dependencies. We can add façades for editing or deleting products without getting overrun with dependencies. This pattern has the added advantage that all our logic for adding products is in one place.
Wrapping Up
So what did we do here? Let's recap:
- We wrapped calls relating to adding products behind a single façade.
- We injected the façade into the Controller, reducing the complexity of the Controller
- We moved the logic concerning which message to show into the façade, simplifying the Controller
View the original article