Download - L04 Software Design Examples
Generic Programming▪ Programming in an data type independent way– Same code is used regardless of the data type▪ Example– Sort can be applied to any data type– Generic collection• Java Collection Framework
▪ Design Principle– Always use the most generic data type possible
Generic Programming▪ All classes extend Object– Allows generic algorithms and data structures
static int find (Object[] a, Object key) { int i; for (i=0;i<a.length;i++) if (a[i].equals(key)) return i; return -1; }
Employee[] staff = new Employee[10]; Employee e1 = new Employee("Dilbert");
staff[x] = e1; int n = find(staff, e1);
Generic Programming▪ Generic collections– ArrayList is an example class that uses Object
ArrayList al = new ArrayList(); al.add (new Employee ("Dilbert")); al.add (new Employee ("Wally")); al.add (new Employee ("Alice"));
Iterator i = al.iterator(); Employee e; while (i.hasNext()) { e = (Employee)i.next(); System.out.println(e.getName()); }
Dilbert Wally Alice
Generic Programming▪ Generic collections– The Collections class is another example
List<Employee> list = new ArrayList<Employee>();
list.add (new Employee ("Dilbert")); list.add (new Employee ("Wally")); list.add (new Employee ("Alice"));
Collections.sort(list); for (Employee e: list) { System.out.println(e); }
Alice Dilbert Wally
Reflection▪ Reflection allows examination and manipulation of objects at
runtime– Get information about a class• Fields, methods, constructors, and super classes• Constants and method declarations belong to an interface– Create an instance of a class whose name is not known until
runtime– Get and set the value of an object's field, even if the field
name is unknown to your program until runtime– Invoke a method on an object, even if the method is not
known until runtime
Reflectionstatic void showMethods(Object o) { Class c = o.getClass(); Method[] theMethods = c.getMethods(); for (int i = 0; i < theMethods.length; i++) { String methodString = theMethods[i].getName(); System.out.println("Name: " + methodString); String returnString = theMethods[i].getReturnType().getName(); System.out.println(" Return Type: " + returnString); Class[] parameterTypes = theMethods[i].getParameterTypes(); System.out.print(" Parameter Types:"); for (int k = 0; k < parameterTypes.length; k ++) { String parameterString = parameterTypes[k].getName(); System.out.print(" " + parameterString); } System.out.println(); } } }
Bla
public class ReflectMethods { public static void main(String[] args) { Polygon p = new Polygon(); showMethods(p); }
Name: getBoundingBox Return Type: java.awt.Rectangle Parameter Types: Name: contains Return Type: boolean Parameter Types: java.awt.geom.Point2D ... Name: toString Return Type: java.lang.String Parameter Types:
Reflection
▪ Reflection is very useful in frameworks– Infrastructure code– “plumbing” – The “Noise”▪ Examples– Create Java objects from XML descriptions– Load classes at runtime and invoke methods– Tools and utilities for development
Reflection
Dynamically Loading Classes▪ Classes can be dynamically loaded at runtime– Offers the flexibility to decide which class to run dynamically– Class names can be specified in configuration files▪ Class class
Class instanceClass = Class.forName("RssFeedReader"); reader = (FeedReader)instanceClass.newInstance();
A) ABB) BAC) ABCD) Compilationfails
QUIZclass A{ public A(String s) { System.out.print("A"); }}
public class B extends A { public B(String s) { System.out.print("B"); } public static void main(String [] args) { new B("C"); } }
A) ABB) BAC) ABCD) Compilationfails
QUIZ
✔
class A{ public A(String s) { System.out.print("A"); }}
public class B extends A { public B(String s) { System.out.print("B"); } public static void main(String [] args) { new B("C"); } }
Software Design PrinciplesSoftware development has over the years established a set of principles that apply to building software
Separation of ConcernCouplingCohesionInformation Hiding
Separation of ConcernThe process of dividing the application into distanct units without overlapping
Concern can be feature, functionality, point of interest, data, or process
Allows for changing one area without affecting other areas
Examples: Presentaion, Domain, Data SourceModel View ControllerHTML, CSS, JavaScript
Separation of ConcernDivide by Feature - vertical
Customer Wallet Single Sign-on
Single Sign-on
Logging Security Session I18N CachingCross-cutting concerns
CouplingRefers to the degree of dependence between objects
The objective is to assign responsibility to classes so that coupling is low
If coupling is high, any change becomes difficult
Loosely coupled systems are easier and cheaper to maintain
Goal is: Low Coupling
CohesionRefers to the degree to which the elements of a module belong together
measures the strength of relationship between pieces of functionality within a given module.
In highly cohesive systems functionality is strongly related
Goal is: High Cohesion
Object Oriented Design▪ Design and implementation of software needs to be of quality– Badly designed, well implemented = problem!– Well designed, badly implemented = problem!
CODEHORROR!!
CODEHORRORDUDE
Object Oriented DesignGood design
Is based on OO principles
Abstracts complex APIs such as J2EE
Is flexible and can be changed
Contains loosely coupled components
Getting StartedSimUDuck is highly successful duck pond simulation gameOriginal design
MallardDuck
display() { }
Duck
quack swim display
// other methods
RedHeadDuck
display() { }
Change Request!But now we need the ducks to FLY
MallardDuck
display() { }
Duck
quack swim display
// other methods
RedHeadDuck
display() { }
Change Request!Ok just add the fly method to Duck
MallardDuck
display() { }
Duck
quack swim display fly // other methods
RedHeadDuck
display() { }
Problem!But not all duck fly – We forgot Rubber Duck!
MallardDuck
display() { }
Duck
quack swim display fly // other methods
RedHeadDuck
display() { }
RubberDuck
display() { }
How can we fix this?Just override fly to do nothing
MallardDuck
display() { }
Duck
quack swim display fly // other methods
RedHeadDuck
display() { }
RubberDuck
quack() { // squeck } fly() { // do nothing }
We even think aheadWe fix all non-flyable and non-quackable ducks as well
Duck
quack swim display fly // other methods
RedHeadDuck
display() { }
RubberDuck
quack() { // squeck } fly() { // do nothing
DecoyDuck
quack() { // no sound } fly() { // do nothing
Codesmell!
MallardDuck
display() { }
Which of the following are disadvantages of using inheritance to provide Duck behaviour?
A) Code is duplicated across subclassesB) Runtime behaviour changes are difficultC) We can’t make ducks danceD) Hard to gain knowledge of all duck behavioursE) Ducks can’t fly and quack at the same timeF) Changes can unintentionally affect other ducks
QUIZ
Which of the following are disadvantages of using inheritance to provide Duck behaviour?
A) Code is duplicated across subclassesB) Runtime behaviour changes are difficultC) We can’t make ducks danceD) Hard to gain knowledge of all duck behavioursE) Ducks can’t fly and quack at the same timeF) Changes can unintentionally affect other ducks
QUIZ
✔
✔
✔
✔
The Problem▪ The problem is this– Derived classes (RubberDuck) are forced to inherit
behaviour they don’t have– Derived classes (RubberDuck) needs to be exposed to the
inner workings of the superclass (Duck)– Users of the base class (Duck) should expect same
functionality– Violation of the Liskov Substitution Principle
Subtypes must be substitutable for their base types. Code that uses references to base class must be able to use objects of derived classes without knowing it.
Liskov Substitution Principle
Trying to fix the ProblemLet’s try using interfaces! Flyable and Quackable
MallardDuck
display() { }fly() { } quack() { }
Duck
swim display
// other methods
RedHeadDuck
display() { }fly() { } quack() { }
RubberDuck
display() { }quack() { // squeck }
DecoyDuck
Codeduplication!
Flyable
fly
Quackable
quack
display() { }
What is the Problem?▪ We tried this– Inheritance changes all subcasses– Interfaces cause code duplication▪ The problem is we are mixing different types of code in one
type of classes▪ Fix– Separate Variation Design Principle– Take what varies and encapsulate it so it wont affect the rest
of the code
Separate Variations Design Principle
Identify the aspects of your application that vary and separate them from what stays the same
flybehaviour
flybehaviour
Separation of Concerns
FlyWithWings flyBehavior = new FlyWithWings();
DATATYPEISTOOSPECIFIC
Duckclass
▪ Separate what changes from what stays the same– Move duck behaviour to a separate class
flybehaviour
quackbehaviour
quackbehaviour
quackbehaviour
Duck Behaviours
flybehaviour
flybehaviour
Separation of Concerns
Duckclass
▪ Duck classes cannot use the concrete behaviour classes! ▪ We need an interface or supertype
flybehaviour
quackbehaviour
quackbehaviour
quackbehaviour
Duck Behaviours
FlyBehaviour <interface>
FlyBehavior flyBehavior = new FlyWithWings();
INTERFACE-POLYMORPHISIM
Loose Coupling with Interfaces▪ Advantages– The ability to change the implementing class of any
application object without affecting calling code– Total freedom in implementing interfaces– The ability to provide simple test implementations and stub
implementations of application interfaces as necessary
Program to Interfaces
Program to an implementation
Program to interface/subtype
Program to unknown creation
Dog d = new Dog();d.bark();
Animal animal = new Dog();animal.makeSound();
Animal animal = getAnimal();animal.makeSound();
We are making classes responsible for their dependencies
Program to InterfacesAnother way is to make the caller responsible for setting the dependency
class Zoo { private Animal animal;
public setAnimal(Animal animal) { this.animal = animal; } ...
animal.makeSound();
Injection happens here
Dependency Injection Design Pattern
Implementing BehaviourWe can add new behaviour without touching the Duck classes
FlyWithWings
fly() { }
FlyBehaviour <interface>
fly();
FlyNoWay
fly() { }
Quack
quack() { }
QuackBehaviour <interface>
quack();
Squeak
quack() { }
implements implements
Integrating BehaviourThe Duck classes will now delegate its flying and quacking behaviour
Duck
QuackBehaviour quackBehaviour; FlyBehaviour flyBehaviour;
swim() { } display() { } performQuack() { } performFly() { }
Behaviour Interfaces
Performing the behaviour
Integrating BehaviourThe Duck classes will now delegate its flying and quacking behaviour
public class Duck { QuackBehavior quackBehavior; ...
public void performQuack() { quackBehavior.performQuack() }
}
We don’t care what this object is behind the interface, we just call it
Integrating BehaviourBut how do we set the behaviour classes?
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); }
}
This is not programming to
interfaces!
Setting the Behaviour DynamicallyUse Dependency Injection - make the caller responsibleAdd two new methods to the Duck classQuackBehavior quackBehavior; FlyBehavior flyBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior }
public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior }
DuckFactory { public Duck getMallardDuck() { Duck duck = new MallardDuck() duck.setFlyBehavior(new FlyWithWings()); duck.setQuackBehavior(new Quack()); return duck; } }
This is an assembler class
Setting the Behaviour DynamicallyUse Dependency Injection - make the caller responsible
Creating systems using composition give flexibilityYou can change the behaviour at runtime
The idea: Don´t think: Mallard is-a flying duck, think: it has-a flying behaviourPut two classes together using compositionOne is member in the other
Object CompositionProblems with concrete inheritance
Class hierarchies are rigidDifficult to change the implementation
Object Composition is more flexibleAllows the behaviour of an object to be altered at run time, through delegating part of its behaviour to an interface and allowing callers to set the implementation of that interface
Generic programmingUsing classes, abstract classes and interfaces can lead to powerful and flexible programs
ReflectionPowerful for building infrastructure
DesignDecouple behaviour of objects from the object them selvesLoosely coupled with interfaces and dependency injectionProgram to interfacesFavour composition over inheritance
Summary
Jobinterviewquestion
YouaregiventheassignmentofcreatingacomponentthatneedstoknowsalesstatisticsofLotterytickets.Youknowthatthereisaanothercomponentinthesystem,SaleServer,thathandlesthesale.Youneedreal-timeinformation.Whatwouldyousuggest?
EXERCISE