01. design pattern
Upcoming SlideShare
Loading in...5
×
 

01. design pattern

on

  • 786 views

A small introduction to design pattern, prepared by me ages ago......

A small introduction to design pattern, prepared by me ages ago......

Statistics

Views

Total Views
786
Views on SlideShare
786
Embed Views
0

Actions

Likes
0
Downloads
31
Comments
1

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

01. design pattern 01. design pattern Presentation Transcript

  •  An object consists of –  data  procedures/operations/methods that operate on that data An object performs an operation when it receives a request from a client. Requests are the only way to get an object to execute an operation. Operations are the only way to change an object‟s internal data. Because of these restrictions, the object‟s internal state is said to be encapsulated.
  •  Encapsulation ensures that the data that an object contains cannot be accessed directly from outside that object, and its representation is invisible from outside the object. Encapsulation is a great way to develop loosely coupled software components. That‟s all I have to say about encapsulation (really, how many times we have read and re-read it ?! But if someone still has some problem with it, speak up), for now.
  •  You can write a problem statement, single out the nouns and verbs, and create corresponding classes and operations. Or you can focus on the collaborations and responsibilities in your system. Or you can model the real world and translate the objects found during analysis into design.
  •  What do you know, it does!!!!!! There is a pattern called Facade which describes how to represent complete subsystems as objects. There is also a pattern called Flyweight that describes how to support huge number of objects at the finest granularities. There are also some other patterns available to help us.
  •  Every operation declared by an object specifies the operation‟s name, the objects it takes as parameters, and the operation‟s return value. This is know as the operation‟s signature. The set of all signatures defined by an object‟s operations is called the interface to the object (beware people, it‟s not the same as our programming language‟s interface construct). An object‟s interface characterizes the complete set of requests that can be sent to the object. Any request that matches a signature in the object‟s interface may be sent to the object.
  •  A type is a name used to denote a particular interface. We speak of an object as having the type X if it accepts all requests for the operations defined in the interface X. An object may have many types, and widely different objects can share a type. Interfaces can contain other interfaces as subsets. We say that a type is a subtype of another if its interface contains the interface of its supertype (huh, what did you just say?!?!). Often we speak of a subtype inheriting the interface of its supertype.
  •  Interfaces are fundamental in object-oriented systems. Objects are known only through their interfaces. There is no way to know anything about an object or to ask it to do anything without going through its interface. An object‟s interface says nothing about its implementation though. Different objects are free to implement requests differently. That means two objects having completely different implementations can have identical interfaces. The run-time association of a request to an object and one of its operations is known as Dynamic Binding.
  •  Dynamic binding means that issuing a request doesn‟t commit you to a particular implementation until run- time. Consequently, you can write programs that expect an object with a particular interface, knowing that any object that has the correct interface will accept the request. A question: Why are we learning this? Ans.: Because Polymorphism depends on it!!!!!!!
  •  Dynamic binding lets you substitute objects that have an identical interfaces for each other at run-time. This substitutability is known as polymorphism. It lets a client object make few assumptions about other objects beyond supporting a particular interface. As a result, it simplifies the definition of clients, decouples objects from each other and lets them vary their relationships to each other at run-time. These inter-changeable classes can enable some other class to display polymorphic behaviors. So what are those POLYMORPHISM stuff that we have learned till now??? I wonder………..
  •  New classes can be defined in terms of existing classes using Inheritance. When a Subclass inherits from a Parent Class, it includes the definitions of all the data and operations that the parent class defines. Objects that are instances of the subclass will contain all data defined by the subclass and its parent classes, and they‟ll be able to perform all operations defined by this subclass and its parents. Let„s call this type of inheritance as Class Inheritance (“nooo, we would like to hear the reason….”) for now.
  •  An abstract class is one whose main purpose is to define a common interface for its subclasses. They are generally used to define a Base Type to be used in class hierarchy. Abstract classes will defer some or all of its implementation to operations defined in subclasses; hence an abstract class cannot be instantiated. The operations that an abstract class declares but doesn‟t implement are called Abstract Operations. Classes that aren‟t abstract (can be instantiated) are called Concrete Classes.
  •  It‟s really, really important to understand the above distinction. An object‟s class defines how the object is implemented. The class defines the object‟s internal State and the implementation of its operations. In contract, an object‟s type only refers to its interface – the set of requests to which it can respond. An object can have many types, and objects of different classes can have the same type.
  •  No, they don‟t mean the same thing (which is obvious now, isn‟t it), but they DO have a close relationship. Because a class defines the operations an object can perform, it also defines the object‟s type. When we say that an object is an instance of a class, we imply that the object supports the interface defined by the class (beware of the conventional Interface…..).
  •  Class inheritance defines an object‟s implementation in terms of another object‟s implementation. In short, it‟s simply a mechanism for code and representation sharing. In contrast, interface inheritance (sometimes called Subtyping) describes when an object can be used in place of another (remember Dynamic Binding?) What do you think? Which one is preferable ?
  •  Class inheritance is basically just a mechanism for extending an application‟s functionality by reusing functionality in parent classes. It lets you define a new kind of object rapidly in terms of an old one. It lets you get new implementations almost for free, inhering most of what you need from existing classes. However, implementation reuse is only half the story. Inheritance‟s ability to define families of objects with identical interfaces is also important. Why? Because Dynamic Binding, and in turn, Polymorphism depends on it (“Huh? How?”).
  •  When inheritance is used carefully (some will say properly), all classes derived from an abstract class will share its interface. This implies that a subclass merely adds or overrides operations and does not hide operations of the parent class. Consequently, all subclasses can then respond to the requests in the interface of this abstract class, making them all subtypes of the abstract class. As a result, all of these subclasses can be switched with one another in run-time, resulting in polymorphic behaviors.
  •  There are two major benefits to manipulating objects solely in terms of the interface defined by abstract classes – 1. Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect. 2. Clients remain unaware of the classes that implement these objects. Clients only know about the abstract classes defining the interface. (Just think about the implications of the above two points) This so greatly reduces implementation dependencies between subsystems that it leads to the following principle of Reusable Object-Oriented design.
  • Program to an Interface, not to an Implementation What does it mean? It means don’t declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class.
  •  There are two different techniques that are used to reuse functionality – 1. Class Inheritance 2. Object Composition As we have learned before, class inheritance lets us define new implementation of one class in terms on another‟s. Reuse by Subclassing in this way is often referred to as White-box reuse, because with this type of inheritance, the internals of parent classes are often visible to subclasses.
  •  Object composition is an alternative to class inheritance. Here, new functionalities is obtained by assembling or composing objects to get more complex functionality. It requires that the objects being composed have well-defined interfaces. This style of reuse is called Black-box reuse, because no internal details of objects are visible. Objects appear only as black boxes. What do you think? Which one is better?
  •  Class inheritance is defined statically at compile-time and is straightforward to use, since it is supported directly by most of the OO languages. Class inheritance also makes it easier to modify the implementation being reused. When a subclass overrides some but not all of the operations, it can affect the operations it inherits as well, assuming the call the overridden operations.
  •  First, you cannot change the implementations inherited from parent classes at run-time, because inheritance is defined at compile-time, resulting in causing difficulties for polymorphism. Second, parent classes often define at least part of their subclasses‟ physical representation. Because inheritance exposes a subclass to details of its parent‟s implementation, it‟s often said that Inheritance Breaks Encapsulation.
  •  Yes, it may sound scary, but it‟s true. The implementation of a subclass becomes so bound up with the implementation of its parent class that any change in the parent‟s implementation will force the subclass to change. This is sometimes called as Implementation Dependencies. Implementation dependencies can cause problems when you‟re trying to reuse a subclass. Should any aspect of the inherited implementation not be appropriate for new problem domains, the parent class must be rewritten or replaced by something more appropriate.
  •  This dependency limits flexibility and ultimately reusability. One cure for this is to inherit from abstract classes, since they usually provide little or no implementation.
  •  Object composition is defined dynamically at run-time through objects acquiring references to other objects, thus being more Polymorphism-friendly. It requires objects to respect each others‟ interfaces, which in turn requires carefully designed interfaces that don‟t stop you from using one object with many others. But there is a pay-off. Because objects are accessed solely through their interfaces, we don‟t break encapsulation. Any object can be replaced at run-time by another as long as it has the same type.
  •  Moreover, because an object‟s implementation will be written in terms of object interfaces, there are substantially fewer implementation dependencies. Favoring object composition over class inheritance helps you keep each class encapsulated and focused on one task. Your classes and class hierarchies will remain small and will be less likely to grow into unmanageable monsters.
  •  On the other hand, a design based on object composition will have more objects ( if fewer classes), and the system‟s behavior will depend on their interrelationships instead of being defined in one class. From the above discussion, we can see that object composition has very, very few bad effects compared to the class inheritance. This gives rise to our second OOP Principle.
  • Favor Object Composition over Class Inheritance. Ideally, you shouldn‟t have to create new components to achieve reuse. You should be able to get all the functionalities you need just by assembling existing components through object composition. But this is rarely the case, because the set of available components is never quite rich enough in practice. Reuse by inheritance makes it easier to make new components that can be composed with old ones. Inheritance and object composition thus work together. Nevertheless, statistics say that designers overuse inheritance as a reuse technique, and designs are made more reusable and simpler by depending more on object composition.
  •  Delegation is a way of making composition as powerful for reuse as inheritance. In delegation, two objects are involved in handling a request –  A receiver object  A delegate object When an object receives a request, it sends the request to a delegate object which will process it and return the result. This is analogous to subclasses deferring requests to parent classes.
  •  The receiver object maintain a reference to the delegated object to delegate the request. When delegating a request, the receiver passes a reference to itself(remember the this pointer?) to the delegated object if the delegated object needs a reference to the receiver object. Example-  A Window class  A Rectangle class  A Circle class Delegation is an extreme example of object composition.
  •  Code reuse Easy to compose behaviors at run-time and to change the way they are composed.  i.e., the Window can become circular at run-time by simply replacing its Rectangle instance with a Circle instance.
  •  Dynamic, highly parameterized software is harder to understand than more static software. There are also run-time inefficiencies, but the human inefficiencies are more important in the long run. Delegation is a good design choice only when it simplifies more than it complicates. It works best when used in highly stylized ways – that is, in standard patterns.
  •  Another technique for reusing functionality is through parameterized types, also known as generics. This technique lets you define a type without specifying all the other types it uses. The unspecified types are supplied as parameters at the point of use. Example –  List class for all types. Parameterized types aren‟t needed at all for languages that doesn‟t have compile-time type checking.
  •  So far, we have learned three different ways to put reuse mechanism at work –  Inheritance  Object Composition  Parameterized Types Inheritance provides default implementations for operations and lets subclasses override them. Parameterized types let you change the types that a class can use.
  •  Neither inheritance nor parameterized types can change at run-time. Object composition allows the behavior to be composed at run-time, but it also requires indirection and can be less efficient.
  •  There are significant differences between run-time and compile-time code structure of an application. The code structure is frozen at compile-time; it consists of classes in fixed inheritance. A program‟s run-time structure consists of rapidly changing networks of communicating objects.
  •  Let us consider the distinction between object Aggregation and Acquaintance and how differently they manifest themselves at compile- and run-times. Aggregation implies that one object owns or is responsible for another object. Generally we speak of an object having or being part of another object. Aggregation implies that an aggregate object and its owner have identical lifetimes. Acquaintance implies that an object merely knows of another object. Sometimes it is called Association or Using relationship between objects. They may request operations of each other, but they aren‟t responsible for each other.
  •  Acquaintance and aggregation are determined more by intent than by explicit language mechanism. The distinction may be hard to see in the compile-time structure, but it‟s significant. Why? Because aggregation relationships tend to be fewer and more permanent than acquaintance. Acquaintances, in contrast, are made and remade more frequently, sometimes existing only for the duration of an operation. Acquaintances are more dynamic as well, making them more difficult to discern in the source code.
  •  With such disparity between a program‟s run-time and compile- time structure, it‟s clear that code won‟t reveal everything about how a system will work. The system‟s run-time structure must be imposed more by the designer than the language. The relationships between objects and their types must be designated with great care, because they determine how good or bad the run-time structure is. Many design patterns capture the distinction between compile- time and run-time structures explicitly (Composite, Decorator, Observer, Chain of Responsibility etc.).
  •  It all started with a simple Duck Simulator. The code that the architect used was – Duck – quack(), swim(), display() MallardDuck – display() RedHeadDuck – display() Everything was going well, the ducks were swimming, quacking perfectly.
  •  Now the management wants the ducks to fly. So the architect added the following method into the supertype – Duck – fly() The designer then thought, “I am Awesome…..”. But then, one day, he got a call………….
  •  In a demonstration, all of the ducks were flying nicely, even the rubber ducks, which shouldn‟t have been the case. The SMART designer thought, “Ok, I could always override the fly() method in the RubberDuck class to do nothing”. But then what will happen if the management wants to include WOODEN DECOY DUCKS into the application? They aren‟t supposed to fly or quack…..
  •  “I could declare two interfaces called Flyable and Quackable, then let all the instances implement them. This way I won‟t have to override those two methods in every duck class that gets added in the future….”. I say, this choice creates a new danger to solve an old one. It completely destroys the code reuse mechanism for those two functionalities and creates a new maintenance nightmare (There is a reason we are calling him capitalized SMART, isn‟t there ?). So, let the OOP principles rescue him in this situation.
  •  So the inheritance didn‟t work out very well, because the Duck behavior keeps changing across the subclasses, and it‟s not appropriate for all subclasses to have those behaviors. Interfaces didn‟t work out well also because any change will cause each of the implementations to change, producing newer bugs along the way. In this situation, let us think of an OOP principle.
  •  The principle says – Identify the aspects of the application that vary and separate them from what stays the same. In other words, take the parts that vary and encapsulate them, so that later you can alter or extend the parts that vary without affecting those that don‟t. As simple it may sound, it forms the basis for almost every design patterns!!!!!!!! All patterns provide a way to let some part of a system vary independently of all other parts.
  •  So, what should we separate from what? Apparently, the following two should be separated –  Fly Behavior  Quack Behavior We are going to separate those methods from the Duck class and create a new set of classes to represent each Duck Behavior. To determine what should be separated from what, and what may cause a change, you will need a good knowledge of the Problem Domain. That‟s why the Object Oriented System Analysis and Design has a section called Requirement Analysis. Do it well, otherwise you will also become capitalized SMART (though it isn‟t always possible/feasible….)!!!!!!
  •  First, we would like to keep things flexible, after all flexibility was the main issue previously. We might want to instantiate a specific Duck object and initialize with specific types of behaviors. While we are there, why not make sure that we can change the behavior of a duck dynamically (e.g., at run-time). Keeping this goal in mind, let us review our first OOP principle – Program to an Interface, not to an implementation.
  •  We will use an interface to represent each duck behavior, and each implementation of a Behavior will implement one of those interfaces. So this time it won‟t be the Duck classes that will implement the flying and quacking interfaces. Instead we‟ll make a set of classes whose entire reason for living is to represent a behavior, and it‟s the behavior class, rather than the Duck class, that will implement the behavior interface.
  •  Public interface Flyable // a strategy (compositor) { public void fly(); } public interface Quackable { public void quack(); }
  •  Public class FlyWithWings implements Flyable // a ConcreteStrategy { public void fly() { System.out.Println(“Fly, fly little Starling…..”); } } Public class Quack implements Quackable { public void quack() { System.out.Println(“Quack, quack, quaaaaaackkk….”); } }
  •  Public class FlyNoWay implements Flyable { public void fly() { // do nothing (for rubber and wooden duck) } } Public class MuteQuack implements Quackable { public void quack() { // do nothing (for wooden duck) } }
  •  Public abstract class Duck // the Context (Composition) { Flyable flyBehavior; Quackable quackBehavior; public Duck() {} public abstract void display(); public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public void swim() { System.out..println ( “ I am swimming!!!! “ ); } }
  •  Public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); // Wait a sec….. flyBahavior = new FlyWithWings() // ?!?!?! } public void display() { // I am a mallard duck } }
  •  Public class MiniDuckSimulator { public static void main(String[] args) { Duck mallard = new MallardDuck(); mallard.performQuack(); mallard.performFly(); } }
  •  Add these two methods to the Duck class - public void setFlyBehavior(Flyable fb) { flyBehavior = fb; } public void setQuackBehavior(Quackable qb) { quackBehavior = qb; }
  •  So, just catch a breathe and think about what you can do with all these…… We have seen an example of our second OOP principle also – Favor Composition over Inheritance
  •  So, instead of thinking the duck behaviors as a set of behaviors, we are thinking of them as a family of algorithms, each one of them performing a specific task in various way. This IS the strategy pattern. In BOOKISH term – The Strategy Pattern defines a family of algorithms, encapsulates each one of them, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. It is also known as Policy Pattern.
  •  Many related classes differ only in their behaviors. Strategies provide a way to configure a class with one of many behaviors. You need different variants of an algorithm. Strategies can be used when these variants are implemented as a class hierarchy of algorithms. An algorithm uses data that clients (objects that requested it to do something) shouldn‟t know about. Use this pattern to avoid exposing complex, algorithm-specific data structures.
  •  A class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own strategy class.
  •  Family of related algorithms. An alternative to subclassing. We could have subclassed the Context class directly to give it different behaviors, but that would have hard-wired the behaviors into Context. It mixes the algorithm implementation with Context‟s, making Context harder to understand, maintain and extend. Elimination of conditional statements.  i.e., void quack(string quack_type){ switch(quack_type){…}} A choice of implementations.
  •  Clients must be aware of different strategies. Clients might be exposed to implementation issues. Therefore it should be used only when the variation in behavior is relevant to client. Communication overhead between Strategy and Context. Tighter coupling may be needed in this case. Increased number of objects. Sometimes it may be reduces by implementing strategies as stateless objects (objects with no data) that contexts can share.
  •  Defining the Strategy and Context interfaces. There are two ways to facilitate communication between them – 1. Context passes data to Strategy as needed 2. Context passes itself to Strategy Making strategy objects optional. This has the advantage that clients don‟t have to deal with Strategy objects at all unless the don‟t like the default behavior.
  •  The famous GoF book Head First Design Patterns Wikipedia Stackoverflow