65
OBJECT ORIENTED PROGRAMMING

01. design pattern

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: 01. design pattern

OBJECT ORIENTED PROGRAMMING

Page 2: 01. design pattern

So, what are Objects?

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.

Page 3: 01. design pattern

So, we have stumbled upon Encapsulation!!!

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.

Page 4: 01. design pattern

How to determine which one should be an object?

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.

Page 5: 01. design pattern

Does design pattern help us to decide what should be an object?

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.

Page 6: 01. design pattern

Method Signatures and Object Interfaces

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.

Page 7: 01. design pattern

Object Types, Subtypes and Supertypes

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.

Page 8: 01. design pattern

Why are we even learning the contents of the previous two slides?

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.

Page 9: 01. design pattern

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!!!!!!!

Page 10: 01. design pattern

So, we have stumbled upon Polymorphism!!!

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………..

Page 11: 01. design pattern

So much stumbling..Why don’t we learn Inheritance by ourselves?!

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.

Page 12: 01. design pattern

Abstract VS. Concrete Classes

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.

Page 13: 01. design pattern

Is an object’s Class and its Type same?

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.

Page 14: 01. design pattern

But we thought they meant the same thing?

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…..).

Page 15: 01. design pattern

Class Inheritance VS Interface Inheritance(What?! Two types of inheritance?!?!)

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 ?

Page 16: 01. design pattern

Why should we use Inheritance?

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?”).

Page 17: 01. design pattern

Why should we use Inheritance?(contd.)

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.

Page 18: 01. design pattern

Why should we use Inheritance?(contd.)

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.

Page 19: 01. design pattern

Our First OOP Principle!!!!! (Phew, finally…)

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.

Page 20: 01. design pattern

Let us now talk about Reuse Mechanism

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.

Page 21: 01. design pattern

Reusing Functionalities (contd.)

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?

Page 22: 01. design pattern

Advantages of using Class Inheritance as Reuse Mechanism

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.

Page 23: 01. design pattern

Disadvantages of using Class Inheritance as Reuse Mechanism

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.

Page 24: 01. design pattern

What?! What?! What?!

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.

Page 25: 01. design pattern

Inheritance Breaks Encapsulation!!! (contd.)

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.

Page 26: 01. design pattern

Consequences of using Object Composition

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.

Page 27: 01. design pattern

Consequences of using Object Composition (contd.)

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.

Page 28: 01. design pattern

Consequences of using Object Composition (contd.)

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.

Page 29: 01. design pattern

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.

Page 30: 01. design pattern

Delegation

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.

Page 31: 01. design pattern

Delegation(Contd.)

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.

Page 32: 01. design pattern

Delegation - Advantage

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.

Page 33: 01. design pattern

Delegation - Disadvantage

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.

Page 34: 01. design pattern

Parameterized Type - Generics

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.

Page 35: 01. design pattern

Code Reuse - Summary

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.

Page 36: 01. design pattern

Code Reuse – Summary(Contd.)

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.

Page 37: 01. design pattern

Relating Run-time and Compile-timeStructure

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.

Page 38: 01. design pattern

Relating Run-time and Compile-timeStructure – an example

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.

Page 39: 01. design pattern

Relating Run-time and Compile-timeStructure – an example (contd.)

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.

Page 40: 01. design pattern

Relating Run-time and Compile-timeStructure(Contd.)

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.).

Page 41: 01. design pattern

Our First Pattern – Strategy (Hi Strategy!!) applied to Ducks (!!!!)

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.

Page 42: 01. design pattern

But, the enemy appears – CHANGE!!!!!

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………….

Page 43: 01. design pattern

Bad Effect of Change………

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…..

Page 44: 01. design pattern

SMART MAN thinks of a plan………

“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.

Page 45: 01. design pattern

First, zero in on the problem

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.

Page 46: 01. design pattern

Our Third OOP Principle - The Perfect Meaning of Encapsulation

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.

Page 47: 01. design pattern

The Separation

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….)!!!!!!

Page 48: 01. design pattern

Designing the Behaviors

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.

Page 49: 01. design pattern

Designing the Behaviors (Contd.)

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.

Page 50: 01. design pattern

Implementing the behaviors

Public interface Flyable // a strategy (compositor)

{

public void fly();

}

public interface Quackable

{

public void quack();

}

Page 51: 01. design pattern

Implementing the behaviors (Contd.)

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….”);

}

}

Page 52: 01. design pattern

Implementing the behaviors (Contd.)

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)}

}

Page 53: 01. design pattern

Implementing the behaviors (Contd.)

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!!!! “ );

}

}

Page 54: 01. design pattern

Implementing the behaviors (Contd.)

Public class MallardDuck extends Duck

{

public MallardDuck()

{

quackBehavior = new Quack(); // Wait a sec…..

flyBahavior = new FlyWithWings() // ?!?!?!

}

public void display()

{

// I am a mallard duck

}

}

Page 55: 01. design pattern

Implementing the behaviors (Contd.)

Public class MiniDuckSimulator

{

public static void main(String[] args)

{

Duck mallard = new MallardDuck();

mallard.performQuack();

mallard.performFly();

}

}

Page 56: 01. design pattern

Remedy of “wait a sec.”

Add these two methods to the Duck class -

public void setFlyBehavior(Flyable fb)

{

flyBehavior = fb;

}

public void setQuackBehavior(Quackable qb)

{

quackBehavior = qb;

}

Page 57: 01. design pattern

Think about it for a sec……

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

Page 58: 01. design pattern

Strategy Pattern – Family of Algorithms

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.

Page 59: 01. design pattern

Applicability: Use this pattern when -

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.

Page 60: 01. design pattern

Applicability: Use this pattern when – (Contd.)

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.

Page 61: 01. design pattern

Consequences of Strategy Pattern

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.

Page 62: 01. design pattern

Consequences of Strategy Pattern (contd.)

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.

Page 63: 01. design pattern

A few Implementation Issues

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.

Page 65: 01. design pattern

THANK YOU