Wednesday, October 10, 2012

Design Patterns


Design principles enhance design of a software system and address 3 main factors,
·        Rigidity – It is very hard to change
·        Fragility – break up of some parts as a side effect of modification
·        Immobility – hard to reuse either in same application or in some other
Design patterns suggests loose coupling between classes / modules. Making less dependent code minimizes the side effects of modifications.
Design Principles
  • Open Close Principle
  • Dependency Inversion Principle
  • Interface Segregation Principle
  • Single Responsibility Principle
  • Liskov's Substitution Principle
General Patterns
  • Lazy Load Pattern
  • Registry Pattern
Behavioral Patterns
  • Chain of Responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Mementr
  • Observer
  • Strategy
  • Template Method
  • Visitor
  • Null Object
Creational Patterns
  • Singleton
  • Factory
    • Factory Method
    • Abstract Factory
  • Builder
  • Prototype
  • Object Pool
Structural Patterns
  • Adapter
  • Bridge
  • Composite
  • Decorate
  • Flyweight
  • Proxy
Lazy load Pattern
Lazy loading the process of delaying the instantiation of an object until it is needed. Lazy programmers are the best programmers.

Registry Pattern
A registry is an object from which other objects can access data, settings and other details (even some objects) like a internal warehouse.

Open Close Principle
Open to extension and Close to modification. This pattern can be used when similar types of objects are kept adding.
E.g. Document /certificate are generated by a method / class. Whenever a certificate is added, a new class/method can be added instead of modifying existing class/method.

Dependency Inversion Principle
A high level class and low level class should be decoupled using abstraction, thereby reducing the dependency. Both the class should not depend on each other. They both should depend on the abstraction.
The term, inversion comes into play, abstraction should not be based on details. Details should be based on abstraction.
DIP pattern is applicable for places where frequent change is encountered.
E.g.




Interface Segregation Principle
Client should not be forced to use method(s) in an interface. Such interfaces with unwanted methods are called as polluted or fat interface. Instead of one such fat interface, many small interfaces can be created.
If a fat interface is designed already, they can be segregated using adapter pattern. Like other DP it requires time in analyzing the code and makes it complex but flexible.


Wrong Design
Interface reportProperties
{
        method setfilenam()
        method setfileProperties()
}
Class ExcelReport implements reportProperties
{
        method setfilename()
        method setfileProperties()
} // Excel can have both filename and file properties
Class HTMLReport implements reportProperties
{
        method setfilenam()
        method setfileProperties()
} // HTML can have only filename not file properties

Correct Design
Interface reportName
{
        method setfilename()
}
Interface reportProperties
{
        method setfileProperties()
}
Class ExcelReport implements reportName, reportProperties
{
        method setfilename ()
        method setfileProperties()
}
Class HTMLReport implements reportName
{
        method setfilenam()
}

Single Responsibility Principle
A class can have only one reason for modification in future. If there is more than a reason, then the class should be spitted to the number of reasons.

Liskov’s substitution Principle
The derived classes should not extend the super class behavior. This is just an extension of open-close principle.

Singleton
Singleton pattern is required when only one instance of a class should be allowed. This is required for critical operations which all users cannot perform. A centralized management is provided for internal and external resources with a global access point.
The class with singleton pattern instantiate itself not more than a time.
E.g. Backup, logging feature, factory implementation as singleton
Memento
A pattern for restoring internal state of an object, without violating encapsulation as a mean to restore the object to its initial / other state when required
This pattern when implemented has 3 components.
·        Memento – This component is usually a class stores the internal state of originator object. It implements two interfaces each for originator and caretaker.
The originator interface allows originator to store any number of state and access any state for restoration.
The Caretaker interface should not allow any operations or any access to the state stored by memento (encapsulation).
·        Originator – Creates a memento object and stores the originator (self) state into it. Fetch memento and restore the originator state.
·        Caretaker – stores a memento. Care taker cannot access memento i.e. communication is one way.
Example – database transactions and undo operations in common applications.

Observer
Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically
There are few events that trigger many actions. With respect to this pattern, the actions are observer of the trigger. Whenever an event happens it should communicate the changes or trigger the actions. This happens in one-to-many relation (can restrict to one to one also).
Consider an example, when an employee separate from an organization. This employee may have other responsibilities. He may be a supervisor for his sub-ordinates, member of a recruitment team. At all the places he should be replaced. Replace recommendation class for all additional works are observers of the basic separation class. The basic separation class is observable. Observer class and observable class stand at opposite ends.
A change in observable class should communicate that to all its observers. To make this happen both observer and observable class should follow an interface or an abstract class.
Observable
interface Observable
{
        function addObserver($observer); 
        // add observer classes which should trigger when a separation happens 
}
 
class separation implements Observable
{
        private $_observers = array();
 
        public function communicate( $name )
        {
               foreach( $this->_observers as $obs)
               {
                       $obs->separated($this, $name);
               }
        }
        public function addObserver($observer)
        {
               $this->_observers []= $observer;
        }
}
 
Observer
interface Observer
{
        function separated($sender, $args);
        // every observer should redefine this method with what to do in their   
           context
}

class recruiter implements Observer
{
        public function separated($objSeparator, $args)
        {
               echo "'$args' separated. Replace with a new recruiter to the    
                        panel" ;
        }
}
class supervisor implements Observer
{
        public function separated($objSeparator, $args)
        {
               echo "'$args' separated. Assign a new supervisor for his/her 
                       subordinates " ;
        }
}
 
Usage
$ul = new separation();
$ul->addObserver( new recruiter() );
$ul->addObserver( new supervisor() );
 
$ul->communicate( "Jack" );
 

 Strategy Pattern

No comments:

Post a Comment