Structural Design Patterns


Structural design patterns 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,
Adapter, Bridge, Composite, Decorator, Facade, Flyweight & Proxy

I.                    Adapter pattern: - This design pattern is used to allow two incompatible types to communicate. Where one class relies upon a specific interface that is not implemented by another class, the adapter acts as a translator between the two types. Pattern will define relationship between objects.

This pattern involves a single class called adapter which is responsible for communication between two independent or incompatible interfaces

It’s usually implemented when requirements changed and we must implement some functionality of classes which interfaces are not compatible with ours.

For more understanding please check below sample code snippet; I have added comments inline for better understanding
       
public interface ITarget//This is an interface which is used by the client to achieve its functionality/request.
        {
            void TestMethodA();
        }

        public class Adapter : Adaptee, ITarget//This is a class which implements the ITarget interface and inherits the Adaptee class. It is used for communication between Client and Adaptee.
        {
            public void TestMethodA()
            {
                TestMethodB();
            }
        }
        public class Adaptee//Adaptee  class  have the functionality that is  required by the client. However, its interface is not compatible with the client.
        {
            public void TestMethodB()
            {
                Console.WriteLine("TestMethodB() is called");
            }
        }


II.                  Bridge Design Pattern: The bridge pattern is a design pattern that separates the abstract elements of a class from its technical implementation. This provides a cleaner implementation of real-world objects and allows the implementation details to be changed easily. So basically Bridge pattern helps to decouple abstraction from implementation.

Understanding: -For sake of explanation consider a switch which can be used to on/off Bulb, TV, and Refrigerator etc.  Here switch is the abstraction and the electronic equipment’s are the implementations. The switch can be applied to any electronic equipment, so the switch is an abstract thinking while the equipment’s are implementations.

For detail understanding in terms of coding refer below code snippet,
       
//Interface for implantation
        public interface IEquipment
        {
            void Start();
            void Stop();
        }

        //Equipment we have
        class Bulb :IEquipment
        {
            public void Start()
            {
                Console.WriteLine("Switch On Bulb");
            }
            public void Stop()
            {
                Console.WriteLine("Switch Off Bulb");
            }
        }
        class TV : IEquipment
        {
            public void Start()
            {
                Console.WriteLine("Switch On TV");
            }
            public void Stop()
            {
                Console.WriteLine("Switch Off TV");
            }
        }


        //Redefined Abstraction Interface
        interface ISwitch
        {
            void On();
            void Off();
        }

        //Bridge
        class Switch:ISwitch
        {
            private IEquipment objEquipment;// Aggregate equipment object reference
            public void setEquipment(IEquipment Equipment)
            {
                objEquipment = Equipment;
            }

            //Interface Implementation
            public void On()
            {
                objEquipment.Start();
            }
            public void Off()
            {
                objEquipment.Stop();
            }
        }


        static void Main(string[] args)
        {
            //Create Implementation Object
            Bulb objBulb = new Bulb();
            TV objTV = new TV();
            //Abstarct Object
            Switch objSwitch = new Switch();

            //Here as you can see implmentation is separate from abstaraction
            objSwitch.setEquipment(objBulb);
            objSwitch.On();
            objSwitch.Off();

            objSwitch.setEquipment(objTV);
            objSwitch.On();
            objSwitch.Off();

        }

I know its bit complex to understand, I have added comments inline for better understanding. So with this code now if the implementation changes it does not affect abstraction and vice versa.


III.                Composite Design Pattern: - “A tree structure of simple and composite objects”-GOF
This design pattern is used when creating hierarchical object models. The pattern defines a manner in which to design recursive tree structures of objects, where individual objects and groups can be accessed in the same manner. When need to manipulate a tree structure of objects, Composite pattern can be used.
So for implementation what we have is one Composite, abstract class which will define behaviors and all classes to use common interface. We will treat the main and leaf object uniformly. 


IV.                Decorator: - The decorator pattern is a design pattern that extends the functionality of individual objects by wrapping them with one or more decorator classes. These decorators can modify existing members and add new methods and properties at run-time.
Basically it is a attaching additional responsibilities to an object dynamically.

Extending object’s functionality can be done statically /compile time by using inheritance or dynamically/run time by wrapping them in an object of a decorator class. Decorator pattern is applied on individual objects, not classes. And it’s an alternative to subclassing. This pattern allows creating a multiple decorators that can be stacked on the top of each other, each time adding a new functionality to the overridden method.


V.                  Facade: -Facade defines a higher-level interface that makes the subsystem easier to use. It provides a unified interface to a set of interfaces in a subsystem.
Facade pattern makes software library easier to use, understand, test and can reduces dependencies. We can say that facade pattern is some kind of wrapper that contains a set of members so they are easy to understand and use.
For more understanding, please refer below code,
In given example we have,
Facade Class-MortgageApplication
·         Knows which subsystem classes are responsible for a request.
·         Delegate client requests to appropriate subsystem objects.
Subsystem classes- Bank, Credit, Loan
·         Implement subsystem functionality.
·         Handle work assigned by the Facade object.
·         Have no knowledge of the facade and keep no reference to it.

In given example, we are checking if customer is eligible for  Loan, so we are creating object of Mortgage class (Facade) and calling to IsEligible method, which will call subsystem methods, HasSufficientSavings, HasNoBadLoans, HasGoodCredit to evaluate customer.

        /// <summary>
        /// Facade Design Pattern.
        /// </summary>
        class MainApp
        {
            /// <summary>
            /// Entry point
            /// </summary>
            static void Main()
            {
                // Facade
                Mortgage mortgage = new Mortgage();
                // Evaluate mortgage eligibility for customer
                Customer customer = new Customer("Mangesh G");

                bool eligible = mortgage.IsEligible(customer, 125000);
                Console.WriteLine("\n" + customer.Name +
                    " has been " + (eligible ? "Approved" : "Rejected"));
                // Wait for user
                Console.ReadKey();
            }
        }

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

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

        /// <summary>
        /// Subsystem class
        /// </summary>
        class Loan
        {
            public bool HasNoBadLoans(Customer c)
            {
                Console.WriteLine("Check loans for " + c.Name);
                return true;
            }
        }

        /// <summary>
        /// Customer class
        /// </summary>
        class Customer
        {
            private string _name;
            // Constructor
            public Customer(string name)
            {
                this._name = name;
            }

            // Gets the name
            public string Name
            {
                get { return _name; }
            }
        }

        /// <summary>
        // Facade Class
        /// </summary>
        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;
            }
        }


VI.                Flyweight: -The flyweight pattern is a design pattern that is used to minimize resource usage when working with very large numbers of objects. This pattern is rarely used, so not going into detail.

VII.              Proxy: - Proxy patterns provide a placeholder for another object to control access to it.
Proxy fundamentally is a class functioning as in interface which points towards the actual class which has data. Proxy can be used when we don’t want to access to the resource or subject directly because of some base of permissions or if we don’t want to expose all of the methods of subject class. This data can be a huge image or a very large object and cannot be duplicated. So multiple proxies can be created and pointed towards the huge memory consuming object and perform operations. This avoids duplication of the object and thus saving memory.
For more understanding, please refer below code,
In given example we have,
Proxy-ImageProxy Class
·         Maintains a reference that lets the proxy access the real subject. Proxy may refer to a Subject if the RealSubject and Subject interfaces are the same.
·         Provides an interface identical to Subject's so that a proxy can be substituted for the real subject.
·         Controls access to the real subject and may be responsible for creating and deleting it.
·         Other responsibilities depend on the kind of proxy:
o    Remote proxies are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space.
o    Virtual proxies may cache additional information about the real subject so that they can postpone accessing it. For example, the ImageProxy from the Motivation caches the real images's extent.
o    Protection proxies check that the caller has the access permissions required to perform a request.
Subject-IImage Interface
·         Defines the common interface for RealSubject and Proxy so that a Proxy can be used anywhere a RealSubject is expected.
RealSubject-Image Class
·         Defines the real object that the proxy represents.

        /// <summary>
        /// Proxy Design Pattern Example
        /// </summary>
        class MainApp
        {
            /// <summary>
            /// Entry point
            /// </summary>
            static void Main()
            {
                // Create proxy
                ImageProxy proxy = new ImageProxy();
                proxy.LoadImage();
                proxy.ImageDiscription();
            }
        }

        /// <summary>
        /// The 'Subject interface
        /// </summary>
        public interface IImage
        {
            void LoadImage();
            string ImageDiscription();           
        }

        /// <summary>
        /// The 'RealSubject' class
        /// </summary>
        class Actualmage : IImage
        {
            public void LoadImage()
            {
                Console.WriteLine("Loaidng Image...");
            }
            public string ImageDiscription()
            {
                Console.WriteLine("Loading image discription form file...");
                return "Image discription";
            }
        }

        /// <summary>
        /// The 'Proxy Object' class
        /// </summary>
        class ImageProxy : IImage
        {
            private Actualmage _Image = new Actualmage();
            public void LoadImage()
            {
                _Image.LoadImage();
            }
            public string ImageDiscription()
            {
                return _Image.ImageDiscription();
            }
        }



Comments