June 9, 2012

Facade pattern


First pattern which I'll try to explore is a structural pattern - Facade.

Before we go to the pattern I think we must understand a concept of subsystem.

Subsystem is a part of large system that consists of a set of elements and relations.
Let's look for simple example for better understanding.


Here you can see a system which consists of four subsystems : UserInterface, OrderManagement, SeatingManagement and Database. Each subsystem has own logic as well as relations to another subsystem(s).


Frequently, you need a simplifier interface to the overall functionality of a complex subsystem.
Facade pattern helps you with it.
Its intent: 
  • Provide an interface to a set of interfaces in subsystem(without changing their);
  • Wrap a complicated subsystem with a simplier interface.
  • Encapsulate subsystem;
We may think about facade pattern as some level of encapsulation of the subsystem since it hides all complexity of subsystem within a more simpler interface. But with facade pattern you lose flexibility (partially) that you may need. Actually you lose flexibility in adding new functionality. However, if you want to change your subsystem by another one or newer, you can do it without any effects. So you getting a flexibility in this case.

Look at image for better understanding what facade pattern provides :
Each pattern I'll implement in two ways :
  • Structural - simple skeleton of pattern;
  • Real-world - real example.
First we explore structural way. Below you can see code snippet for subsystem:


class SubSystemA
{
 public void MethodA()
 {
  Console.WriteLine("SubSystemA.MethodA");
 }
}

class SubSystemB
{
 public void MethodB()
 {
  Console.WriteLine("SubSystemB.MethodB");
 }
}

class SubSystemC
{
 public void MethodC()
 {
  Console.WriteLine("SubSystemC.MethodC");
 }
}


Each interface within subsystem has one method which yields some text to the console.
Let's look at Facade class:

class Facade
{
 SubSystemA subSystemA;
 SubSystemB subSystemB;
 SubSystemC subSystemC;

 public Facade()
 {
  subSystemA = new SubSystemA();
  subSystemB = new SubSystemB();
  subSystemC = new SubSystemC();
 }

 public void MethodOne()
 {
  Console.WriteLine("*** Facade.MethodOne ***");
  subSystemA.MethodA();
  subSystemB.MethodB();
  subSystemC.MethodC();
 }

 public void MethodTwo()
 {
  Console.WriteLine("*** Facade.MethodTwo ***");
  subSystemC.MethodC();
  subSystemA.MethodA();            
 }
}

Here you can see how I've implemented "complicated" logic in methods MethodOne and MethodTwo.
Simple usage of Facade class:


Facade facade = new Facade();

facade.MethodOne();
facade.MethodTwo();

Console.ReadLine();

And in result on the console window you may see something like this:


Let's explore real-world example of usage of Facade pattern.
Do you like pizza?
I love it!


Consider, simple pizzas order.
You call to pizza call center and speak with a service representative.
You say which concrete pizzas you want, delivery address and your contact phone number.
On what, girl's beautiful voice replies how much will it costs for you.

In a while, you are look like the boy at the photo. :)



Return to Facade pattern.
For example, our pizza service (subsystem) is very large and it consists of three departments (interfaces) : order department, discount department, delivery department.

Look at code for our departments:


Code:
class DeliveryDepartment
{
 public int GetTimeForDelivering(string address)
 {
  if (address.ToLower().Contains("kyiv"))
   return 30;

  return 100;
 }
}

class DiscountDepartment
{
 public double GetDiscount(int pizzaAmount)
 {
  if (pizzaAmount == 0)
   throw new Exception("At least one pizza must be");

  switch (pizzaAmount)
  {
   case 1:
    return 0;
   case 2:
    return 10;
   case 3:
    return 25;
   default:
    return 50;
  }
 }
}

class OrderDepartment
{

 public double GetPrice(int pizzaAmount)
 {
  double price = pizzaAmount * 50;

  return price;
 }

}

And "facade" class:

class PizzaCallCenter
{
 OrderDepartment orderDepartment;
 DiscountDepartment discountDepartment;
 DeliveryDepartment deliveryDepartment;

 public PizzaCallCenter()
 {
  orderDepartment = new OrderDepartment();
  discountDepartment = new DiscountDepartment();
  deliveryDepartment = new DeliveryDepartment();
 }

 public double GetPrice(string address, int pizzaAmount, int desirableDeliveryTime)
 {
  var discount = discountDepartment.GetDiscount(pizzaAmount);
  var deliveryTime = deliveryDepartment.GetTimeForDelivering(address);

  var pizzaPrice = orderDepartment.GetPrice(pizzaAmount);
  var deliveryPrice = deliveryTime * 5; 
  
  var priceWithDiscount = pizzaPrice - (pizzaPrice * discount) / 100.0;
  var desirableDeliveryPrice = deliveryPrice + Math.Max(deliveryTime - desirableDeliveryTime, 0) * 0.1;

  var totalPrice = priceWithDiscount + desirableDeliveryPrice;

  return totalPrice;
 }

 public int GetTimeForDelivering(string address)
 {
  return deliveryDepartment.GetTimeForDelivering(address);
 }

}

So our pizza call center has two methods :

  • GetPrice (..) - return price(for pizzas based on available discounts plus delivery to destination based on desirableDeliveryTime);
  • GetTimeForDelivering(..) - return minutes needed to deliver pizza to destination.
Usage of PizzaCallCenter class:


PizzaCallCenter pizzaCallCenter = new PizzaCallCenter();

string address = "1/2, Khreshchatyk, Kyiv";
int pizzaAmount = 3;
int desirableDeliveryTime = 20;

Console.WriteLine("Calling ...");
var price = pizzaCallCenter.GetPrice(address, pizzaAmount, desirableDeliveryTime);

Console.WriteLine("Address : {0}\nAmount of pizza : {1}\nDelivery time : {2}\nPrice : {3}", address, pizzaAmount, desirableDeliveryTime, price);
Console.WriteLine();

address = "201 Varick Street, 12th floor, New York";

Console.WriteLine("Calling ...");
var deliveryTime = pizzaCallCenter.GetTimeForDelivering(address);
Console.WriteLine("Address : {0}\nDelivery time : {1}", address, deliveryTime);

Console.ReadLine();

On console window you can see something like this:

That's all. Hopefully, everything was clear for you.

Source of facade pattern you can see on GitHub via this LINK.

Have a nice day :)

P.S. By the way, Ukraine and Poland host Euro-2012. And today will be a game between Germany and Portugal. What do you think about result of this game?

2 comments:

  1. Я думаю, що сьогодні зустрінеться Німеччина та Португалія і ніяка свиня не зможе передбачити результат матчу ;)

    ReplyDelete
    Replies
    1. Germany has played very well :)
      Gomez's a big football player.

      Delete