practical object oriented design techniques

39
Practical object oriented design techniques Satish Annapureddy Director, Technology Myrio Corporation

Upload: tamyra

Post on 11-Feb-2016

37 views

Category:

Documents


3 download

DESCRIPTION

Satish Annapureddy Director, Technology Myrio Corporation. Practical object oriented design techniques. Introduction. Focus Practical techniques and guidelines, that can be used daily, to create “good” object-oriented designs. How to design objects – fields and methods - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Practical object oriented design techniques

Practical object oriented design techniques

Satish AnnapureddyDirector, Technology

Myrio Corporation

Page 2: Practical object oriented design techniques

Introduction● Focus

– Practical techniques and guidelines, that can be used daily, to create “good” object-oriented designs.

● How to design objects – fields and methods● How to design relationships and interactions

– Inheritance, composition, interfaces● Thread-safe design with OO.● Java design idioms

Page 3: Practical object oriented design techniques

Proper intialization● Objects can be seen as finite-state

machines.– Instance variables store state. Methods

change state by changing instance variables.

● The challenge is in keeping the object in a valid state at all times.– Data hiding is imperative!

● Proper initialization ensures that the object starts in a valid state.

Page 4: Practical object oriented design techniques

Proper Initialization (contd)– Design constructors and initializers so that

there is no way the object can start in an invalid state.

– Throw exception to indicate invalid constructor/method parameters eg., java.lang. IllegalArgumentException

– If for some reason, it is needed to allow the object to start in an invalid state, throw exception to indicate improper usage. eg., java.lang.IllegalStateException.

Page 5: Practical object oriented design techniques

Proper finalization● Finalizers – what they are NOT for -

– System resources – file handles, sockets, memory etc. are finite. Free them when no longer needed.

● In Java, garbage collector runs finalizer when it frees unreferenced object (not when running out of some non-memory resource).

● Provide an API to allow clients to release resources. eg., open() and close().

Page 6: Practical object oriented design techniques

Proper finalization (contd)● Finalizers – what are they for?

– In Java, for releasing memory allocated in native methods via JNI.

– Last attempt at releasing non-memory resources.

● “Attempt” since finalizers may not run on live objects at time of exit.

– In Java, java.lang.Runtime.runFinalizersOnExit() ensures that finalizers are run on all live objects at exit.

Page 7: Practical object oriented design techniques

Designing fields● Use a variable per purpose.

– In version 1, let's say that the temperature sensor is capable of tracking temps >= 0;

public class TemperatureSensor { ... public int getTemperature() { return temp; } public boolean isSensorWorking() { return temp < 0; // dual-use } private int temp;}

Page 8: Practical object oriented design techniques

Designing fields (contd)● In version 2, the sensor can track

negative temperatures too.public class TemperatureSensor { ... public int getTemperature() { return temp; } public boolean isSensorWorking() { return working == true; } private int temp; private boolean working;}

Page 9: Practical object oriented design techniques

Designing methods● Minimize method coupling as much

as possible.– The less a method (and hence a class)

knows about other classes, the better.– Take in the most relevant object and

output the object actually affected.● Least coupled are utility methods (static

methods that depend only on input parameters and class constants)

Page 10: Practical object oriented design techniques

Designing methods (contd)// encode x-www-form-urlencoded strings

public class XWWWFormURLEncoder {

public void encode(URLString str) {

...}

}

Note: x-www-form-urlencoded is applied to a String, usually in the context of a URL, but not necessarily.

Page 11: Practical object oriented design techniques

Designing methods (contd)● Maximize Cohesion – each method

must focus on a single conceptual task. eg., insert(..), delete(..), open(..) etc.– Why?

● Changes localized. Removes side-effects.● More readable.

– How?● Avoid passing control parameters. Create

multiple methods instead.

Page 12: Practical object oriented design techniques

Designing methods (contd)public class Account {

// low cohesion: control data (type) is passed in.

// split into multiple methods: creditAccount(..), debitAccount(..), clearAccount(..)

public void updateBalance(int type, float amount) {

if(type == CREDIT) {...}else if(type == DEBIT) {...}else if(type == CLEAR) {...}else if...

}

}

Page 13: Practical object oriented design techniques

Encapsulation and information hiding

● Encapsulation and information hiding are two different concepts!– Encapsulation refers to bundling data and

operations that use that data.– Information hiding refers to hiding

implementation details of the class– You can have encapsulation without

information hiding.● Good OO requires both done right!

– Objects should be intelligent entities. Do not separate methods from related data.

Page 14: Practical object oriented design techniques

Encapsulation and information hiding (contd)

● Information hiding guidelines– Don't expose data.– Don't expose the fact that certain attribute

is derived – use getDuration(...) instead of computeDuration(...)

– Don't expose details on internal data structures – getMap() instead of getTreeMap().

– Don't give out mutable handles to internal data.

Page 15: Practical object oriented design techniques

Encapsulation and information Hiding (contd)

public class SortedList {

public void insert(ListElement obj) {

// insert at appropriate position so that// the list remains sorted.

}

public ListElement getElement(int position) {

return elementAt(position); // direct access to internal data.}

}

Notes: client code can use getElement().setX(...) so that the list is

no longer sorted.

Page 16: Practical object oriented design techniques

Encapsulation and Information Hiding (contd)

● get/set expose implementation details via interfaces– For example, code that uses int getX()

breaks when the return type is changed to float.

– Objects should be designed to be intelligent. ie., request services not data.

● By understanding how the class will be used, you can eliminate most get/set methods by providing services instead.

Page 17: Practical object oriented design techniques

UI Design without getters and setters

● Problem: If get/set are removed, an object must somehow know how to present its UI.– But, it is not feasible for an object to

support all possible UIs.● Solution: Use the Builder pattern

– Use a Builder helper object and provide for export and import via interfaces.

● This basically moves the get/set to the Builder (UI) object from the business class object.

Page 18: Practical object oriented design techniques

UI design without getters and setters (contd)

public class TestingStats {

public interface Exporter {

void setScores(float[] scores);void setAvg(float avg);..

}

public void export(Exporter builder) {

builder.setScores(scores);builder.setAvg(avg);...

}

private float[] scores;

private float avg, median, mean; // and others

...

}

Page 19: Practical object oriented design techniques

UI Design without getters and setters (contd)

public class TestingStatsUI extends JPanel implements Exporter {

public void setScores(float[] scores) { graph.setData(scores); }

public void setAvg(float avg) { add(new JtextField(“”+avg)); }

...

private SuperPowerfulGraphWidget graph;

}

public void showUI(...) {

...

testingStats.export(testingStatsUI);

...

testingStatsUI.show();

...

}

Page 20: Practical object oriented design techniques

Thread-safe design● Heap (and method area) is common,

stacks are local among threads.● Methods cause state transitions. But

during the transition, the state becomes invalid. Atomicity is required to ensure that the invalid state is not exposed to other threads.

● Guarding critical sections prevents race conditions – read/write and write/write conflicts.

Page 21: Practical object oriented design techniques

Thread-safe design (contd)● For example, insert() below has both Read/Write and

Write/Write conflicts.public class LinkedList {

public void insert(LinkElement new_element) { tmp = cur.next; cur.next = new_element; new_element.next = tmp;}public void printList() { for(LinkElement elem = start; elem != null; elem=elem.next) print(elem);}...

}

Page 22: Practical object oriented design techniques

Thread-safe design (contd)● Three approaches

– Protect critical sections with mutexes.● Another reason why fields MUST be private!● Identify critical sections and use lock/unlock to

enter and leave critical sections.– Synchronizing everything degrades performance and

may also result in deadlocks.● Most common and most powerful approach.

Thread coordination (wait and notify) are impossible without locks.

– Use immutable objects.● Inherently thread-safe - object state does not

change after creation.

Page 23: Practical object oriented design techniques

Thread-safe design (contd)● Identify critical sections but no locking.

– Critical sections that read are left alone.– Critical sections that write are changed to create new

immutable objects to reflect new states.– eg., java.lang.String

– Thread-safe wrappers● Front-end the object with a thread-safe

wrapper that has the same interface. (Decorator pattern)

● Flexible – make objects thread-safe only when really needed.

● Eg., Collections.synchronizedSet(Set set)

Page 24: Practical object oriented design techniques

Exceptions● When to throw exceptions?

– To indicate an abnormal event: If your method encounters an “error condition”, throw an exception.

● What constitutes an “error condition”?– Is EOF an error condition?

● While reading byte by byte into a buffer?● When only 3 bytes of a 4-byte int are read?

– To indicate broken contract: caller violates pre-condition.

● What about calling java.util.Iterator.next() when java.util.Iterator.hasNext() returns false?

Page 25: Practical object oriented design techniques

Exceptions (contd)– A Runtime exception – NoSuchElementException is

thrown.● What about a method that expects non-null

String but is passed null instead?– A runtime exception – IllegalArgumentException is

thrown.– What exception to throw?

● The client programmer should handle “abnormal” conditions by throwing specific checked exceptions. These are declared and hence enforced by the compiler.

● Broken contracts indicate bad code and should be fixed before release. Runtime exceptions are appropriate for this purpose.

Page 26: Practical object oriented design techniques

Inheritance vs Composition● Inheritance makes use of dynamic

binding and polymorphism.– Great for adding new behaviors via

subclassing.– Bad when superclass's interface needs

modifications.● Changes to public method signatures ripple to

all the clients that use the superclass or any of its subclasses.

● Composition delegates actual implementation to a back-end class.

Page 27: Practical object oriented design techniques

Inheritance vs Composition (contd)

– Composition: Advantages● Better isolates back-end changes: The front-

end implementation will change to reflect the back-end change, but the front-end interface may remain the same.

● Subclasses are more rigid than front-end classes. eg., changing return type on an inherited method is not possible.

● Composition allows optimizations – lazy instantiation of back-end objects and dynamically changing back-end objects.

Page 28: Practical object oriented design techniques

Inheritance vs Composition (contd)

– Composition: Disadvantages● Polymorphism makes inheritance far more

effective than composition for adding new implementations (new subclasses).

– Composition with interfaces solves this problem.● Delegation approach in composition might

affect performance.● How to choose between the two?

– Inheritance ONLY for permanent is-a relationships. Otherwise, use composition.

● Do not use inheritance just to reuse implementation or for polymorphism

Page 29: Practical object oriented design techniques

Inheritance vs Composition (contd)

Consider the following classes:

public class MediaAsset {

public String getURL() {

...}

}

public class MovieAsset extends MediaAsset { ... }

public class MoviePlayer {

public void setupMovie(MovieAsset movie) {

BandwidthController.reserveBandwidth(authenticationInfo, movie.getURL());

...}

}

Page 30: Practical object oriented design techniques

Inheritance vs CompositionLet us say that getURL() method in MediaAsset is changed to return URL.

public class MediaAsset {

public StringURL getURL() {

}

...

}● Now, MoviePlayer object is broken since it uses MovieAsset which extends

MediaAsset. If we used composition instead, the change would not ripple past MovieAsset (the front-end class)

public class MovieAsset {

public String getURL() {

return mediaAsset.getURL().getPath();}

private MediaAsset mediaAsset;

}

Page 31: Practical object oriented design techniques

Composition with interfaces● Interfaces allow for more

polymorphism than inheritance.– Inheritance with polymorphism allows for

using a subclass in place of a superclass.● With interfaces you are not limited to one

inheritance hierarchy. Any class that implements the interface can be substituted.

– Composition with interfaces is just as powerful and flexible as inheritance with polymorphism.

– Interfaces do not suffer from the “diamond” problem.

Page 32: Practical object oriented design techniques

Composition with interfaces(contd)

● No multiple inheritance of implementation (methods and non-private fields) and hence no ambiguity.

– Interfaces allow implementation to be totally decoupled from interface.

● How to use interfaces:– Various subsystems should communicate

with each other via interfaces.● Use interfaces to abstract out subsystems that

can have many implementations.– Use interfaces to represent functionality

common to different class hierarchies.

Page 33: Practical object oriented design techniques

Composition with interfaces (contd)

● In the previous example, MovieAsset cannot be substituted for MediaAsset if it is implemented using composition. By combining composition with interface, we can easily solve this problem!

public interface Asset {

String getAssetURL();

...

}

public class MediaAsset implements Asset { .. }

public class MovieAsset implements Asset {

// delegate to mediaAsset instance.

}

Page 34: Practical object oriented design techniques

Implementation inheritance issues

● Implementation inheritance couples subclass method implementation to superclass even if no data is exposed.– Any superclass implementation changes

may break the subclasses.● Protected member variables are worse!

● Don't make any assumptions about or use artifacts of superclass implementation– Better yet, consider using interfaces.

Page 35: Practical object oriented design techniques

Implementation inheritance issues (contd)

public class Base {

public void foo() { ... }

...

}

public class Foo extends Base {

public void foo() { ... }

public boolean equals(Object obj) { ... }

...

}

// foo1 and foo2 are two instances of Foo and foo1.equals(foo2) returns true.

Hashtable htbl = new Hashtable().put(foo1, “Foo 1”);

Now, htbl.get(foo2) should return “Foo 1”. But it returns null. Why?

Page 36: Practical object oriented design techniques

Abstract base classes and interfaces

● Combine interfaces with abstract base classes to get the best of both worlds– Implement an interface with default

implementation in an abstract base class.– Class hierarchy is used as a common code

repository. If the implementation changes radically, you can go back to using the interface.

Page 37: Practical object oriented design techniques

Abstract base class and interfaces (contd)

public interface RTSPClient {

void setup(..);

void teardown(..);

void play(..);

void pause(..);

void describe(..);

...

}

public abstract class AbstractRTSPClient implements RTSPClient {

abstract void setup(...); // other methods as well.

// connection management, keep alive timer impl. Etc.

}

Page 38: Practical object oriented design techniques

Abstract base classes and interfaces (contd)

public class NcubeRTSPClient extends AbstractRTSPClient {

void setup(...) {

// compose request headers

// send request and receive response

// activate keep-alive based on session timeout in response

// update state machine

}

}

public class BitBandRTSPClient implements RTSPClient {

void setup() { bitband_setup(...); }

native void bitband_setup(...); // RTSP and more is done in native library

}

Page 39: Practical object oriented design techniques

References● OODP/Java design articles by Bill Venners at

http://www.artima.com● OODP/Java design articles by Allen Holub at

http://www.holub.com● OODP series at

http://www.javaworld.com/channel_content/jw-oop-index.shtml