Structural Design Pattern for .NET


STRUCTURAL:

Structural design patterns are patterns that describe how objects and classes can be combined and form a large structure and that ease design by identifying a simple way to realize relationships between entities. There are seven structural patterns described. They are as follows:

StructDesiPatte1.gif

Adapter:

In the Adapter pattern two incompatible types can communicate between each other as the adapter acts as a translator between the two. This is something like when we convert an interface of one class into an interface expected by the client. It is like the problem of inserting a new three-prong electrical plug into an old two-prong wall outlet; some kind of adapter or intermediary is necessary.

Model:

StructDesiPatte2.gif

That additional plug is an 'Adaptor'.

UML Diagram:

StructDesiPatte3.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AdapterPattern
{
 class Example
   {
    static void Main()
     {

      // Non-adapted chemical compound
        Compound unknown = new Compound("Unknown");
        unknown.Display();

     // Adapted chemical compounds
        Compound water = new RichCompound("Water");
        water.Display();
        Compound ethanol = new RichCompound("Ethanol");
        ethanol.Display();
        Console.ReadKey();
     }
   }
 class Compound
  {
   protected string _chemical;
   protected float _boilingPoint;
   protected float _meltingPoint;
   protected string _molecularFormula;

 // Constructor
   public Compound(string chemical)
    {
     this._chemical = chemical;
    }
   public virtual void Display()
    {
     Console.WriteLine("\nCompound: {0} ------ ", _chemical);
    }
  }
 class RichCompound : Compound
  {
   private ChemicalDatabank _bank;
   public RichCompound(string name)
   : base(name)
   {  }
   public override void Display()
   {
   // Adaptee
    _bank = new ChemicalDatabank();
    _boilingPoint = _bank.GetCriticalPoint(_chemical, "B");
    _meltingPoint = _bank.GetCriticalPoint(_chemical, "M");
    _molecularFormula = _bank.GetMolecularStructure(_chemical);
       base.Display();
          Console.WriteLine(" Formula: {0}", _molecularFormula);
          Console.WriteLine(" Melting Pt: {0}", _meltingPoint);
          Console.WriteLine(" Boiling Pt: {0}", _boilingPoint);
    }
   }

   // 'Adaptee' class
     class ChemicalDatabank
    {

    // databank 'legacy API'
     public float GetCriticalPoint(string compound, string point)
      {

    // Melting Point
        if (point == "M")
         {
          switch (compound.ToLower())
           {
            case "water": return 0.0f;
            case "ethanol": return -114.1f;
            default: return 0f;
           }
         }

     // Boiling Point
        else
         {
          switch (compound.ToLower())
           {
            case "water": return 100.0f;
            case "ethanol": return 78.3f;
            default: return 0f;
           }
         }
      }

 public string GetMolecularStructure(string compound)
   {
    switch (compound.ToLower())
     {
      case "water": return "H20";
      case "ethanol": return "C2H5OH";
      default: return "";
     }
   }
public double GetMolecularWeight(string compound)
   {
    switch (compound.ToLower())
     {
      case "water": return 18.015;
      case "ethanol": return 46.0688;
      default: return 0d;
     }
   }
 }
}


Bridge:

The Bridge pattern is quite a bit more complex than the other patterns. It is used to form large object structures across many disparate objects; also separate out the interface from its implementation. The switch of the fan is one of the best examples of this pattern.

Model:

StructDesiPatte4.gif

UML Diagram:

StructDesiPatte5.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BridgePattern
{
 class Example
  {
   static void Main()
   {

 // Create RefinedAbstraction
    Customers customers = new Customers("India");

 // Set ConcreteImplementor
    customers.Data = new CustomersData();

 // Exercise bridge
    customers.Show();
    customers.Next();
    customers.Show();
    customers.Next();
    customers.Show();
    customers.Add("Kapil Chawla");
    customers.ShowAll();
    Console.ReadKey();
   }
 }

// 'Abstraction' class
 class CustomersBase
 {
  private DataObject _dataObject;
  protected string group;
  public CustomersBase(string group)
  {
   this.group = group;
  }

// Property
   public DataObject Data
   {
    set { _dataObject = value; }
    get { return _dataObject; }
   }
   public virtual void Next()
   {
    _dataObject.NextRecord();
   }
   public virtual void Prior()
   {
    _dataObject.PriorRecord();
   }
   public virtual void Add(string customer)
   {
    _dataObject.AddRecord(customer);
   }
   public virtual void Delete(string customer)
   {
    _dataObject.DeleteRecord(customer);
   }
   public virtual void Show()
   {
    _dataObject.ShowRecord();
   }
   public virtual void ShowAll()
   {
    Console.WriteLine("Customer Group: " + group);
    _dataObject.ShowAllRecords();
   }
 }

// 'RefinedAbstraction' class
 class Customers : CustomersBase
  {
   public Customers(string group)
   : base(group)
   {    }
   public override void ShowAll()
   {

// Add separator lines
    Console.WriteLine();
    Console.WriteLine("------------------------");
    base.ShowAll();
    Console.WriteLine("------------------------");
   }
  }

// 'Implementor' abstract class
 abstract class DataObject
  {
   public abstract void NextRecord();
   public abstract void PriorRecord();
   public abstract void AddRecord(string name);
   public abstract void DeleteRecord(string name);
   public abstract void ShowRecord();
   public abstract void ShowAllRecords();
 }

// 'ConcreteImplementor' class
  class CustomersData : DataObject
  {
   private List<string> _customers = new List<string>();
   private int _current = 0;
   public CustomersData()
   {
    _customers.Add("Rahul Narang");
    _customers.Add("Dolly Sinha");
    _customers.Add("Aaliya Bose");
    _customers.Add("Prashant Tondon");
    _customers.Add("Amrita Singhal");
   }
public override void NextRecord()
  {
   if (_current <= _customers.Count - 1)
    {
     _current++;
    }
  }
public override void PriorRecord()
  {
   if (_current > 0)
    {
     _current--;
    }
  }
public override void AddRecord(string customer)
  {
   _customers.Add(customer);
  }
public override void DeleteRecord(string customer)
  {
   _customers.Remove(customer);
  }
public override void ShowRecord()
  {
   Console.WriteLine(_customers[_current]);
  }
public override void ShowAllRecords()
  {
   foreach (string customer in _customers)
    {
     Console.WriteLine(" " + customer);
    }
  }
 }
}


Composite:

To compose an object and present the hierarchies in tree-structures the composite design pattern is used. It allows clients to treat individual objects equally. The client never knows that it is working on an object which has many other objects inside it.

Model:

StructDesiPatte6.gif

UML Diagram:

Example:

StructDesiPatte7.gif

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CompositePattern
{
 class Example
  {
   static void Main()
   { 

   // Create a tree structure
      Composite root = new Composite("root");
      root.Add(new Leaf("Leaf A"));
      root.Add(new Leaf("Leaf B"));
      Composite comp = new Composite("Composite X");
      comp.Add(new Leaf("Leaf XA"));
      comp.Add(new Leaf("Leaf XB"));
      root.Add(comp);
      root.Add(new Leaf("Leaf C"));

   // Add and remove a leaf
      Leaf leaf = new Leaf("Leaf D");
      root.Add(leaf);
      root.Remove(leaf);

  // Recursively display tree
      root.Display(1);
      Console.ReadKey();
    }
  }

 // 'Component' abstract class
  abstract class Component
  {
   protected string name;

 // Constructor
   public Component(string name)
    {
     this.name = name;
    }
    public abstract void Add(Component c);
    public abstract void Remove(Component c);
    public abstract void Display(int depth);
  }

// Composite Class
 class Composite : Component
  {
   private List<Component> _children = new List<Component>();
   public Composite(string name)
   : base(name)
   {    }
   public override void Add(Component component)
   {
    _children.Add(component);
   }
   public override void Remove(Component component)
   {
    _children.Remove(component);
   }
   public override void Display(int depth)
   {
    Console.WriteLine(new String('-', depth) + name);

// Recursively display child nodes
    foreach (Component component in _children)
    {
     component.Display(depth + 2);
    }
   }
  }

// Leaf Class
class Leaf : Component
 {
  public Leaf(string name)
  : base(name)
   {    }
  public override void Add(Component c)
   {
    Console.WriteLine("Cannot add to a leaf");
   }
  public override void Remove(Component c)
   {
    Console.WriteLine("Cannot remove from a leaf");
   }
  public override void Display(int depth)
   {
    Console.WriteLine(new String('-', depth) + name);
   }
 }
}


Decorator:

When there is a need to add the additional functionality to objects dynamically then we use the decorator pattern. It provides an alternative to subclassing for extending an object's functionality. It is also known as Wrapper and allows creating inherited classes which are a sum of all parts of the parent.

Model:

StructDesiPatte8.gif

UML Diagram:

StructDesiPatte9.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecoratorPattern
{
 class Example
  {
   static void Main()
   {
  // Create book
    Book book = new Book("Worley", "Inside ASP.NET", 10);
    book.Display();

  // Create video
    Video video = new Video("Spielberg", "Jaws", 23, 92);
    video.Display();

  // Make video borrowable, then borrow and display
    Console.WriteLine("\nMaking video borrowable:");
    Borrowable borrowvideo = new Borrowable(video);
    borrowvideo.BorrowItem("Customer #1");
    borrowvideo.BorrowItem("Customer #2");
    borrowvideo.Display();
    Console.ReadKey();
   }
  }

//'Component' abstract class
 abstract class LibraryItem
  {
   private int _numCopies;

// Property
   public int NumCopies
   {
    get { return _numCopies; }
    set { _numCopies = value; }
   }
   public abstract void Display();
  }

//'ConcreteComponent' class
 class Book : LibraryItem
 {
  private string _author;
  private string _title;

// Constructor
  public Book(string author, string title, int numCopies)
   {
    this._author = author;
    this._title = title;
    this.NumCopies = numCopies;
   }
  public override void Display()
   {
    Console.WriteLine("\nBook ------ ");
    Console.WriteLine(" Author: {0}", _author);
    Console.WriteLine(" Title: {0}", _title);
    Console.WriteLine(" # Copies: {0}", NumCopies);
   }
 }

//'ConcreteComponent' class
 class Video : LibraryItem
  {
   private string _director;
   private string _title;
   private int _playTime;

 // Constructor
   public Video(string director, string title,
   int numCopies, int playTime)
   {
    this._director = director;
    this._title = title;
    this.NumCopies = numCopies;
    this._playTime = playTime;
   }
   public override void Display()
    {
     Console.WriteLine("\nVideo ----- ");
     Console.WriteLine(" Director: {0}", _director);
     Console.WriteLine(" Title: {0}", _title);
     Console.WriteLine(" # Copies: {0}", NumCopies);
     Console.WriteLine(" Playtime: {0}\n", _playTime);
    }
   }

//'Decorator' abstract class
 abstract class Decorator : LibraryItem
  {
   protected LibraryItem libraryItem;
   public Decorator(LibraryItem libraryItem)
   {
    this.libraryItem = libraryItem;
   }
   public override void Display()
   {
    libraryItem.Display();
   }
 }

//'ConcreteDecorator' class
class Borrowable : Decorator
 {
  protected List<string> borrowers = new List<string>();
  public Borrowable(LibraryItem libraryItem)
  : base(libraryItem)
  {    }
  public void BorrowItem(string name)
  {
   borrowers.Add(name);
   libraryItem.NumCopies--;
  }
  public void ReturnItem(string name)
  {
   borrowers.Remove(name);
   libraryItem.NumCopies++;
  }
  public override void Display()
  {
   base.Display();
   foreach (string borrower in borrowers)
    {
     Console.WriteLine(" borrower: " + borrower);
    }
   }
  }
}


Facade:

The Façade design pattern provides a simple interface to large code. It makes things easier by hiding the details of the implementation and also can wrap a poorly designed collection of APIs with a single well-designed API.

Model:

StructDesiPatte10.gif


UML Diagram:

StructDesiPatte11.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FacadePattern
{
 class Example
  {
   static void Main()
    {

   // Facade
      Mortgage mortgage = new Mortgage();

  // Evaluate mortgage eligibility for customer
      Customer customer = new Customer("Mr. Vijay");
      bool eligible = mortgage.IsEligible(customer, 125000);
      Console.WriteLine("\n" + customer.Name +
      " has been " + (eligible ? "Approved" : "Rejected"));
      Console.ReadKey();
    }
  }

//'Subsystem ClassA' class
class Bank
 {
  public bool HasSufficientSavings(Customer c, int amount)
   {
    Console.WriteLine("Check bank for " + c.Name);
    return true;
   }
 }

//'Subsystem ClassB' class
class Credit
 {
  public bool HasGoodCredit(Customer c)
   {
    Console.WriteLine("Check credit for " + c.Name);
    return true;
   }
 }

//'Subsystem ClassC' class
class Loan
 {
  public bool HasNoBadLoans(Customer c)
  {
   Console.WriteLine("Check loans for " + c.Name);
   return true;
  }
 }
class Customer
 {
  private string _name;
  public Customer(string name)
  {
   this._name = name;
  }

// Get name
  public string Name
  {
   get { return _name; }
  }
}

//'Facade' class
class Mortgage
 {
  private Bank _bank = new Bank();
  private Loan _loan = new Loan();
  private Credit _credit = new Credit();
  public bool IsEligible(Customer cust, int amount)
   {
    Console.WriteLine("{0} applies for {1:C} loan\n",
    cust.Name, amount);
    bool eligible = true;

 // Check creditworthyness of applicant
    if (!_bank.HasSufficientSavings(cust, amount))
     {
      eligible = false;
     }
    else if (!_loan.HasNoBadLoans(cust))
     {
      eligible = false;
     }
    else if (!_credit.HasGoodCredit(cust))
     {
      eligible = false;
     }
 return eligible;
  }
 }
}

FlyWeight:


When we need to create thousands or more objects that share some common information, we use a flyweight pattern. For example we need to print visiting cards for all employees in the organization. So we have two parts of data; one is the variable data i.e. the employee name and the other is static data i.e. address. We can minimize memory by just keeping one copy of the static data and referencing the same data in all objects of variable data. So we create different copies of variable data, but reference the same copy of static data. With this we can optimally use the memory.

Model:

StructDesiPatte12.gif

UML Diagram:

StructDesiPatte13.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FlyweightPattern
{
 class Example
  {
   static void Main()
   {

 // Arbitrary extrinsic state
   int extrinsicstate = 22;
   FlyweightFactory factory = new FlyweightFactory();

// Work with different flyweight instances
   Flyweight fx = factory.GetFlyweight("X");
   fx.Operation(--extrinsicstate);
   Flyweight fy = factory.GetFlyweight("Y");
   fy.Operation(--extrinsicstate);
   Flyweight fz = factory.GetFlyweight("Z");
   fz.Operation(--extrinsicstate);
   UnsharedConcreteFlyweight fu = new
   UnsharedConcreteFlyweight();
   fu.Operation(--extrinsicstate);
   Console.ReadKey();
   }
  }

// Flyweightfactory class
class FlyweightFactory
 {
  private Hashtable flyweights = new Hashtable();
  public FlyweightFactory()
  {
   flyweights.Add("X", new ConcreteFlyweight());
   flyweights.Add("Y", new ConcreteFlyweight());
   flyweights.Add("Z", new ConcreteFlyweight());
  }
  public Flyweight GetFlyweight(string key)
  {
   return ((Flyweight)flyweights[key]);
  }
 }

//'Flyweight' abstract class
abstract class Flyweight
 {
  public abstract void Operation(int extrinsicstate);
 }

// 'ConcreteFlyweight' class
class ConcreteFlyweight : Flyweight
 {
  public override void Operation(int extrinsicstate)
  {
   Console.WriteLine("ConcreteFlyweight: " + extrinsicstate);
  }
 }

//'UnsharedConcreteFlyweight' class
 class UnsharedConcreteFlyweight : Flyweight
  {
   public override void Operation(int extrinsicstate)
   {
    Console.WriteLine("UnsharedConcreteFlyweight: " +
    extrinsicstate);
   }
  }
}

Proxy:

The Proxy pattern is used when you need to represent an object that is complex or time consuming to create with a simpler one. If creating an object is expensive in time or computer resources, Proxy allows you to postpone this creation until you need the actual object.

Model:

StructDesiPatte14.gif

UML Diagram:

StructDesiPatte15.gif

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProxyPattern
{
 class Example
  {
   static void Main()
    {

  // Create math proxy
     MathProxy proxy = new MathProxy();

  // Do math
     Console.WriteLine("8 + 6 = " + proxy.Add(8, 6));
     Console.WriteLine("8 - 6 = " + proxy.Sub(8, 6));
     Console.WriteLine("8 * 6 = " + proxy.Mul(8, 6));
     Console.WriteLine("8 / 6 = " + proxy.Div(8, 6));
     Console.ReadKey();
    }
  }

//'Subject interface
public interface IMath
 {
  double Add(double x, double y);
  double Sub(double x, double y);
  double Mul(double x, double y);
  double Div(double x, double y);
 }

//'RealSubject' class
class Math : IMath
 {
  public double Add(double x, double y) { return x + y; }
  public double Sub(double x, double y) { return x - y; }
  public double Mul(double x, double y) { return x * y; }
  public double Div(double x, double y) { return x / y; }
 }

//'Proxy Object' class
class MathProxy : IMath
 {
  private Math _math = new Math();
  public double Add(double x, double y)
   {
    return _math.Add(x, y);
   }
  public double Sub(double x, double y)
   {
    return _math.Sub(x, y);
   }
  public double Mul(double x, double y)
   {
    return _math.Mul(x, y);
   }
  public double Div(double x, double y)
   {
    return _math.Div(x, y);
   }
 }
}

  


Similar Articles