You are on page 1of 74

UNIT-IV

Object Design: Reuse and Patterns

1. Reuse: Identification of existing solutions


Use of inheritance Off-the-shelf components and additional solution objects Design patterns

2. Interface specification

3. Object model restructuring 4. Object model optimization

Describes precisely each class interface Transforms the object design model to improve its understandability and extensibility Transforms the object design model to address performance criteria such as response time or memory utilization.

Select Subsystem

Specification

Reuse

Identifying missing attributes & operations Specifying visibility

Identifying components

Adjusting components Specifying types & signatures Identifying patterns Specifying constraints

Specifying exceptions

Adjusting patterns

Check Use Cases

Restructuring Revisiting inheritance Collapsing classes

Optimization Optimizing access paths Caching complex computations Delaying complex computations

Realizing associations

class diagrams can be used to model both the application domain and the solution domain. Application objects, also called domain objects, represent concepts of the domain that the system manipulates. Solution objects represent support components that do not have a counterpart in the application domain, such as persistent data stores, user interface objects, or middleware. During analysis, we identify application objects, their relationships, and attributes and operations. During system design, we identify subsystems and most important solution objects. During object design, we refine and detail both sets of objects and identify any remaining solution objects needed to complete the system.

Inheritance

Analysis activity
Taxonomy Inheritance for Reuse

Object Design

Inheritance detected by specialization

Inheritance detected by generalization

Specification Inheritance

Implementation Inheritance

Inheritance is used to achieve two different goals Description of Taxonomies


Description of Taxonomies Interface Specification

Interface Specification

Used during requirements analysis Activity: identify application domain objects that are hierarchically related Goal: make the analysis model more understandable Used during object design Activity: identify the signatures of all identified objects Goal: increase reusability, enhance modifiability and extensibility

Car drive() brake() accelerate()

Superclass:
public class Car { public void drive() {} public void brake() {} public void accelerate() {} }

Subclass:
LuxuryCar

playMusic() ejectCD() resumeMusic() pauseMusic()

public class LuxuryCar extends Car { public void playMusic() {} public void ejectCD() {} public void resumeMusic() {} public void pauseMusic() {} }

Implementation inheritance
Also called class inheritance Goal:
Extend an applications functionality by reusing functionality from the super class Inherit from an existing class with some or all operations already implemented

The use of inheritance for the sole purpose of reusing code.

Specification Inheritance
Also called sub typing Goal:

The classification of concepts into type hierarchies is called specification inheritance.

Inherit from a specification The specification is an abstract class with all operations specified, but not yet implemented.

Implementation Inheritance: The combination of inheritance and implementation


The Interface of the superclass is completely inherited Implementations of methods in the superclass ("Reference implementations") are inherited by any subclass

Specification Inheritance: The combination of inheritance and specification


The Interface of the superclass is completely inherited Implementations of the superclass (if there are any) are not inherited.

A very similar class is already implemented that does almost the same as the desired class implementation List
Add() Remove() Already implemented

Example: I have a List class, I need a Stack class How about subclassing the Stack class from the List class and implementing Push(), Pop(), Top() with Add() and Remove()?

Push() Pop() Top()

Stack

Problem with implementation inheritance:


The inherited operations might exhibit unwanted behavior. Example: What happens if the Stack user calls Remove() instead of Pop()?

Inheritance: Extending a Base class by a new operation or overwriting an operation. Delegation: Catching an operation and sending it to another object.
List
+Add() +Remove()

Stack
+Push() +Pop() +Top()

List
Add() Remove()

Inheritance

Stack
+Push() +Pop() +Top()

Delegation

Delegation is a way of making composition as powerful for reuse as inheritance In delegation two objects are involved in handling a request from a Client
The Receiver object delegates operations to

the Delegate object The Receiver object makes sure, that the Client does not misuse the Delegate object.
Client Receiver delegates to

calls

Delegate

A class is said to delegate to another class if it implements an operation by merely resending a message to another class. Delegation makes clear the dependencies between the reused class and the new class.

Hashtable

put (key, element) get (key) :object J containsKey (key):boolean containsValue (element):boolean

Myset

put (element) containsValue (element):boolean

class Myset extends HashtabJe {

/* Constructor omitted */

MySet() { } void put (Object element) { if (!containsKey (element)) { put (element, thiS); }} boolean containsValue (Object element) { return containsKey (element); }

/* other methods omitted */


}

Hashtable

put (key, element) get (key) :object J containsKey (key):boolean containsValue (element):boolean

Myset

put (element) containsValue (element):boolean

class Myset { Private Hashtable table;

/* Constructor omitted */

MySet() { table= hashtable(); } void put (Object element) { if (!containsKey (element)) { Table.put (element, thiS); }} boolean containsValue (Object element) { (return table.containsKey (element)); }

/* other methods omitted */


}

FUNCTIONS

THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT

Derived types must be completely substitutable for their base types.

The Liskov Substitution Principle is a way of ensuring that inheritance is used correctly. If a function does not satisfy the LSP, then it probably makes explicit reference to some or all of the subclasses of its superclass. Such a function also violates the Open-Closed Principle, since it may have to be modified whenever a new subclass is created.

Most people would think that a Square is a special kind of Rectangle and there for intuitively inherit their Square class from the Rectangle class to be able to reuse code. However if you study the given image you will notice that the Rectangle have a couple of traits that the Square does NOT and vice versa. First of all the Square has only *ONE* attribute; size, while the Rectangle have *TWO* attributes; width & height.

22

Consider the following Rectangle class:

public class Rectangle { private double width; private double height; public Rectangle(double w, double h) { width = w; height = h; } public double getWidth() {return width;} public double getHeight() {return height;} public void setWidth(double w) {width = w;} public void setHeight(double h) {height = h;} public double area() {return (width * height); }

Now, how about a Square class? Clearly, a square is a rectangle, so the Square class should be derived from the Rectangle class

Observations:

A square does not need both a width and a height as attributes, but it will inherit them from Rectangle anyway. So, each Square object wastes a little memory, but this is not a major concern. The inherited setWidth() , setHeight() methods are not really appropriate for a Square, since the width and height of a square are identical.

So we'll need to override setWidth() and setHeight

Here's the Square class:

// A Square class. public class Square extends Rectangle { public Square(double s) {super(s, s); } public void setWidth(double w) { super.setWidth(w); super.setHeight(w); } public void setHeight(double h) { super.setHeight(h); super.setWidth(h); } }

Check this out!

public class TestRectangle { // Define a method that takes a Rectangle reference. public static void testLSP(Rectangle r) { r.setWidth(4.0); r.setHeight(5.0); System.out.println("Width is 4.0 and Height is 5.0" + ", so Area is " + r.area()); if (r.area() == 20.0) System.out.println(OK!\n"); else System.out.println(Error!\n"); }

public static void main(String args[ ]) { //Create a Rectangle and a Square Rectangle r = new Rectangle(1.0, 1.0); Square s = new Square(1.0); // Now call the method above. According to the // LSP, it should work for either Rectangles or // Squares. Does it?? testLSP(r); testLSP(s); } }

Test program output: Width is 4.0 and Height is 5.0, so Area is 20.0 OK! Width is 4.0 and Height is 5.0, so Area is 25.0 Error! Looks like we violated the LSP!

A mathematical square might be a rectangle, but a Square object is not a Rectangle object. Behavior of a Square object is not consistent with the behavior of a Rectangle object! Behaviorally, a Square is not a Rectangle! A Square object is not polymorphic with a Rectangle object. If you inherit your Square class from your Rectangle class, then you might currently get around it by hiding the width property of the Rectangle somehow, maybe by convention, and then just let the size property of the Square forward the call to height or something similar, but this is always wrong! Having to override these simple methods is a clue that this might not be an appropriate use of inheritance!

The problem is when you hit "real life scenarios", especially with Single Inheritance programming languages - like for instance C# and Java.
Because if you're not supposed to break LSP you will often tend to repeat code a LOT. In C# you cannot inherit from multiple classes like you can in C and other MI (Multiple Inheritance languages) you cannot create "small, lightweight carrier classes" for you to inherit from to not break LSP !

30

Delegation

Inheritance

Flexibility: Any object can be replaced at run time by another one (as long as it has the same type Inefficiency: Objects are encapsulated. Straightforward to use Supported by many programming languages Easy to implement new functionality Inheritance exposes a subclass to the details of its parent class Any change in the parent class implementation forces the subclass to change (which requires recompilation of both)

Abstract method:
A method with a signature but without an implementation (also called abstract operation)

Abstract class:
A class which contains at least one abstract method is called abstract class

Interface: An abstract class which has only abstract methods

VendingMaschine totalReceipts collectMoney() makeChange() dispenseItem()

dispenseItem() must be implemented in each subclass. We do this by specifying the operation as abstract. Abstract operations are written in UML in italics.

CoffeeMachine numberOfCups coffeeMix heatWater() addSugar() addCreamer() dispenseItem()

SodaMachine cansOfBeer cansOfCola chill() dispenseItem()

CandyMachine bagsofChips numberOfCandyBars dispenseItem()

Rewriteable Method: A method which allow a reimplementation.


In Java methods are rewriteable by default, i.e. there is no special keyword.

Strict inheritance
The subclass can only add new methods to the superclass, it cannot over write them

If a method cannot be overwritten in a Java program, it must be prefixed with the keyword final.

Car drive() brake() accelerate()

Superclass:
public class Car { public final void drive() {} public final void brake() {} public final void accelerate() {} }

Subclass:
LuxuryCar

playMusic() ejectCD() resumeMusic() pauseMusic()

public class LuxuryCar extends Car { public void playMusic() {} public void ejectCD() {} public void resumeMusic() {} public void pauseMusic() {} }

Original Java-Code:
class Device { int serialnr; public final void help() {.} public void setSerialNr(int n) { serialnr = n; } } class Valve extends Device { Position s; public void on() { . } }

help() not overwritable

setSerialNr() overwritable

Original Java-Code:
class Device { int serialnr; public final void help() {.} public void setSerialNr(int n) { serialnr = n; } } class Valve extends Device { Position s; public void on() { . } }

New Java-Code :
class Device { int serialnr; public final void help() {.} public void setSerialNr(int n) { serialnr = n; } } class Valve extends Device { Position s; public void on() { } public void setSerialNr(int n) { serialnr = n + s.serialnr; } } // class Valve

What are Design Patterns? A design pattern describes a problem which occurs over and over again in our environment Then it describes the core of the solution to that problem, in such a way that you can use the this solution a million times over, without ever doing it the same twice Design pattern has four elements:1) Name that uniquely identifies the pattern from other patterns 2) Problem description : describes the situation in which the pattern can be used. 3) Solution: stated as a set of collaboration classes and interfaces. 4) Consequences: describes the trade-off and alternatives to be considered with respect to design goals.

This pattern decouples the interface of a class from its implementation. Also know as a Handle/Body pattern Allows different implementations of an interface to be decided upon dynamically.

Description
we need to decouple an Abstraction from an Implementor, because we need to substitute different Implementors for a given Abstraction without any impact on a calling Subsystem. This is realized by providing an Abstraction class that implements its services in terms of the methods of an Implementor interface. Concrete Implementors that need to be substituted refine the Implementor interface.

Taxonomy in Application Domain

Taxonomy in Solution Domain

It provides a bridge between the Abstraction (in the application domain) and the Implementor (in the solution domain)

Decouples an abstraction from its implementation so that the two can vary independently This allows to bind one from many different implementations of an interface to a client dynamically Design decision that can be realized any time during the runtime of the system

The bridge pattern can be used to provide multiple implementations under the same interface
Interface to a component that is incomplete (only Stub code is available), not yet known or unavailable during testing If seat data are required to be read, but the seat is not yet implemented (only stub code available), or only available by a simulation (AIM or SART), the bridge pattern can be used:
VIP Seat (in Vehicle Subsystem) GetPosition() SetPosition()
imp

SeatImplementation

Stub Code

AIMSeat

SARTSeat

Arena imp LeagueStore

Delegation
LeagueStoreImplementor

Stub Store Implementor

XML Store Implementor

JDBC Store Implementor

Inheritance

Adapter Pattern: Connects incompatible components.

Also known as a wrapper. Uses both inheritance and delegation. The adapter pattern lets classes work together that couldnt otherwise because of incompatible interfaces

It converts the interface of one component into another interface expected by the other (calling) component Used to provide a new interface to existing legacy components (Interface engineering, reengineering)

Client Or client class

New System Or Pattern Interface

Old System (Legacy System) Or Implementer class

ClientInterface Request()

LegacyClass ExistingRequest()

adaptee Adapter Request()

Client

ClientInterface Request()

LegacyClass ExistingRequest()

adaptee

Inheritance

Adapter
Request()

Delegation

The adapter pattern uses inheritance as well as delegation: - Interface inheritance is used to specify the interface of the Adapter class. - Delegation is used to bind the Adapter and the Adaptee

Two adapter patterns:


Class adapter:
Uses multiple inheritance to adapt one interface to another

Object adapter:
Uses single inheritance and delegation

Object adapters are much more frequent. We cover only object adapters (and call them adapters).

Different algorithms exists for a specific task


We can switch between the algorithms at run time

Examples of tasks:
Different collision strategies for objects in video games Parsing a set of tokens into an abstract syntax tree (Bottom up, top down) Sorting a list of customers (Bubble sort, mergesort, quicksort)

Different algorithms will be appropriate at different times

If we need a new algorithm, we can add it without disturbing the application or the other algorithms.

First build, testing the system, delivering the final product

define an interface that lets strategy accessing its data.

Policy

defines an interface common to all supported algorithms

Context
ContextInterface()

Strategy
AlgorithmInterface

ConcreteStrategyA
AlgorithmInterface()

ConcreteStrategyB
AlgorithmInterface()

ConcreteStrategyC
AlgorithmInterface()

Policy decides which ConcreteStrategy is best in the current Context.

Client

Policy TimeIsImportant SpaceIsImportant

Database SelectSortAlgorithm() Sort()

SortInterface

Sort()

BubbleSort
Sort()

QuickSort
Sort()

MergeSort
Sort()

policy
Mobile Application

Context = {Mobile, Home, Office} strategy class


NetworkInterface open() close() send() receive()

LocationManager Context class


NetworkConnection send() receive() setNetworkInterface()

Client class

Ethernet open() close() send() receive()

WaveLAN open() close() send() receive()

UMTS open() close() send() receive()

AbstractFactory Client CreateProductA CreateProductB

AbstractProductA

ProductA1

ProductA2

ConcreteFactory1

AbstractProductB

CreateProductA CreateProductB
ProductB1 ConcreteFactory2 CreateProductA CreateProductB ProductB2

Initiation Assocation: Class ConcreteFactory2 initiates the associated classes ProductB2 and ProductA2

Independence from Initialization or Representation or platform Manufacturer Independence Constraints on related products Cope with upcoming change

Abstract Factory offers the interface for creating a family of related objects

IntelligentHouse

HouseFactory createBulb() createBlind()

EIBFactory createBulb() createBlind()

LuxmateFactory createBulb() createBlind()

LightBulb

Blind

EIBBulb

LuxmateBulb

EIBBlind

LuxmateBlind

You want to build a user interface You want to provide menus You want to make the menus reusable across many applications
The applications only know what has to be done when a command from the menu is selected You dont want to hardcode the menu commands for the various applications

Such a user interface can easily be implemented with the Command Pattern.

Command
Invoker Client Receiver action1() action2()
binds ConcreteCommand1

execute()

binds

execute()

ConcreteCommand2
execute()

Client (in this case a user interface builder) creates a ConcreteCommand and binds it to an action operation in Receiver Client hands the ConcreteCommand over to the Invoker which stores it (for example in a menu) The Invoker has the responsibility to execute or undo a command (based on a string entered by the user)

The Command abstract class declares the interface supported by all ConcreteCommands. The client is a class in a user interface builder or in a class executing during startup of the application to build the user interface. The client creates concreteCommands and binds them to specific Receivers, this can be strings like commit, execute, undo. So all user-visible commands are sub classes of the Command abstract class. The invoker - the class in the application program offering the menu of commands or buttons - invokes theconcreteCommand based on the string entered and the binding between action and ConcreteCommand.

The command pattern can be nicely used to decouple boundary objects from control objects:
Boundary objects such as menu items and buttons, send messages to the command objects (I.e. the control objects) Only the command objects modify entity objects

When the user interface is changed (for example, a menu bar is replaced by a tool bar), only the boundary objects are modified.

Match play() replay()

Move execute()

binds GameBoard TicTacToeMove

execute()
ChessMove execute()

Models tree structures that represent part-whole hierarchies with arbitrary depth and width. The Composite Pattern lets client treat individual objects and compositions of these objects uniformly There are times when a program needs to manipulate a tree data structure and it is necessary to treat both Branches as well as Leaf Nodes uniformly. Eg File System.

abstraction for leafs and composites

Client

Component

stores child components in addition to implementing methods defined by the component interface.

Leaf
Operation()

Composite
Operation() AddComponent RemoveComponent() GetChild()

Children

Software System:
Definition: A software system consists of subsystems which are either other subsystems or collection of classes Composite: Subsystem (A software system consists of subsystems which consists of subsystems , which consists of subsystems, which...) Leaf node: Class

User

Software System

Class Subsystem

Children

The Graphic Class represents both primitives (Line, Circle) and their containers (Picture)
Client Graphic

Line
Draw()

Circle
Draw()

Picture
Draw() Add(Graphic g) RemoveGraphic) GetChild(int)

Children

Similarities:
Difference:

Both are used to hide the details of the underlying implementation.

The adapter pattern is geared towards making unrelated components work together
Applied to systems after theyre designed (reengineering, interface engineering). Inheritance followed by delegation

A bridge, on the other hand, is used up-front in a design to let abstractions and implementations vary independently.
Green field engineering of an extensible system New beasts can be added to the object zoo, even if these are not known at analysis or system design time. Delegation followed by inheritance

A framework is a reusable partial application that can be specialized to produce custom applications. The key benefits of frameworks are reusability and extensibility:
Reusability leverages of the application domain knowledge and prior effort of experienced developers Extensibility is provided by hook methods, which are overwritten by the application to extend the framework.

Frameworks are targeted to particular technologies, such as data processing or cellular communications, or to application domains, such as user interfaces or real-time avionics. Frameworks uses Hook methods . Hook methods systematically decouple the interfaces and behaviors of an application domain from the variations required by an application in a particular context.

Frameworks can be classified by their position in the software development process:


Infrastructure frameworks Middleware frameworks Enterprise application frameworks

Frameworks can also be classified by the techniques used to extend them:


Whitebox frameworks Blackbox frameworks

Infrastructure frameworks aim to simplify the software development process


Used internally, usually not delivered to a client.

Middleware frameworks are used to integrate existing distributed applications


Examples: MFC, DCOM, Java RMI, WebObjects, WebSphere, WebLogic Enterprise Application [BEA].

Enterprise application frameworks are application specific and focus on domains


Example of application domains: telecommunications, avionics, environmental modeling, manufacturing, financial engineering, enterprise business activities.

White-box frameworks:

Black-box frameworks:

Extensibility achieved through inheritance and dynamic binding. Existing functionality is extended by subclassing framework base classes and overriding specific methods (so-called hook methods) Extensibility achieved by defining interfaces for components that can be plugged into the framework. Existing functionality is reused by defining components that conform to a particular interface These components are integrated with the framework via delegation.

Class Library:
Provide a smaller scope of reuse Less domain specific Class libraries are passive; no constraint on the flow of control

Framework:
Classes cooperate for a family of related applications. Frameworks are active; they affect the flow of control.

Components:
Self-contained instances of classes Plugged together to form complete applications Can even be reused on the binary code level
The advantage is that applications do not have to be recompiled when components change

Framework:
Often used to develop components Components are often plugged into blackbox frameworks.

WebBrowser

WebObjects

WebServer StaticHTML

WebObjectsApplication WOAdaptor WoRequest Template WORequest EOF

RelationalDatabase

You might also like