Date post: | 01-Nov-2014 |
Category: |
Technology |
Upload: | olafur-andri-ragnarsson |
View: | 86 times |
Download: | 5 times |
Lecture 04Software Design 2
Agenda Programming with Objects– Classes– Interfaces– Generic programming– Reflection
Software Design– Ducks…
Reading Barbin Introduction, 1 Core Principles– Separation of concerns (SoC)– Coupling– Cohesion– Information Hiding
Don’t Repeat Yourself Polymorphism Optional:– http://docs.oracle.com/javase/tutorial/
Generic Programming
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()); }
DilbertWallyAlice
Generic Programming Generic collections– The Collections class is another exampleList<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);}
AliceDilbertWally
Reflection
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(); } } }
Reflection
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
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) BDB) DBC) BDCD) Compilation fails
QUIZclass Top { public Top(String s) { System.out.print("B"); } }public class Bottom2 extends Top { public Bottom2(String s) { System.out.print("D"); } public static void main(String [] args) { new Bottom2("C"); System.out.println(" "); } }
A) BDB) DBC) BDCD) Compilation fails
QUIZ
✔
class Top { public Top(String s) { System.out.print("B"); } }public class Bottom2 extends Top { public Bottom2(String s) { System.out.print("D"); } public static void main(String [] args) { new Bottom2("C"); System.out.println(" "); } }
Software Design
Object Oriented Design Design and implementation of software
needs to be of quality– Badly designed, well implemented = problem!– Well designed, badly implemented = problem!
CODEHORROR!!
CODE HORROR DUDE
Object Oriented Design Good design
Is based on OO principles
Abstracts complex APIs such as J2EE
Is flexible and can be changed
Contains loosely coupled components
Example from Head First Design Patterns
Getting Started SimUDuck is highly successful duck pond
simulation game Original design
Change Request But now we need the ducks to FLY
Problem! But not all duck fly – We forgot Rubber
Duck!
How can we fix this? Just override fly and quack to do nothing
We even think ahead We fix all non-flyable and non-quackable
ducks as wellCode smell!
Which of the following are disadvantages of using inheritance to provide Duck behavior?
A) Code is duplicated across subclassesB) Runtime behavior changes are difficultC) We can’t make ducks danceD) Hard to gain knowledge of all duck behaviorsE) Ducks can’t fly and quack at the same timeF) Changes can unitentionally 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
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.
BarbaraLiskov
The Liskov Substitution Principle All code operating with reference to the
base class should be completely transparent to the type of the inherited object
It should be possible to substitute an object of one type with another within the same class hierarchy
Inheriting classes should not perform any actions that will invalidate the assumptions made by the base class
LSP Examplepublic class Rectangle {
protected int _width; protected int _height; public int getWidth() { return _width; } public int getHeight() { return _height; } public void setWidth(int width) { _width = width; } public void setHeight(int height) { _height = height; }}
LSP Examplepublic class Square extends Rectangle {
public void setWidth(int width) { _width = width; _height = width; }
public void setHeight(int height) { _height = height; _width = _height; } }
Implementation convenience
LSP Exampleimport junit.framework.Assert;import org.junit.Test;
public class RectangleTests {
@Test public void areaOfRectangle() {
Rectangle r = new Square(); r.setWidth(5); r.setHeight(2); // Will Fail - r is a square and sets // width and height equal to each other. Assert.assertEquals(r.getWidth() * r.getHeight(),10); }}
Trying to fix the Problem Let’s try using interfaces– Flyable and Quackable Code duplication!
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
Identify the aspects of your application that vary and separate them from what stays the same
Separation of Concerns Separate what changes from what stays
the same– Move duck behavior to a separte classes
FlyWithWings flyBehavior = new FlyWithWings();DATA TYPE IS TOO SPECIFIC
Separation of Concerns But the Duck classes cannot use the
concrete behavior classes! – We need an interface or supertype
FlyBehavior flyBehavior = new FlyWithWings();
INTERFACE - POLYMORPHISIM
The Interface Design Principle
Program to an interface, not an implementation
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 an interfacesProgram 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();
Program to an interfacesDependency Injection– Make the caller responsible for setting the
dependencyprivate Animal animal;
public setAnimal(Animal animal){ this.animal = animal;}...
animal.makeSound();
Injection happens here, in the set-method
LOOSE COUPLING = BEAUTIFUL!
Implementing Behavior We can add new behaviors without
touching the Duck classes
Integrating the Behavior The Duck classes will now delegate its
flying and quacking behavior
Behavior interfaces
Perform the Bahavior
Integrating the Behavior Using the behavior
public class Duck { QuackBehavior quackBehavior; ...
public void performQuack() { quackBehavior.performQuack() }
}
We don’t care what kind of object this is, all we care is that it knows how to
quack!
Integrating the Behavior Setting the behavior
public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); }
}
This is not programming to an interface!
Setting Behavior Dynamically Add two new methods to the Duck class Dependency Injection
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; }}
Setting Behavior Dynamically The idea– Don´t think: Mallard is-a flying duck, think: it
has-a flying behavior– Putting two classes together where one is a
member in the other is a composition Creating systems using composition give
flexibilty– You can change the behavior at runtime
Composition Design Principle
Favor composition over inheritance
Object Composition Problems with concrete inheritance– Class hierarchy can get rigid– Difficult to change the implementation
Object Composition is more flexible – Allows 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
Summary OO Programming is powerful– If used correctly– Remember Encapsulation, Interfaces,
Polymorphism Generic programming– Using classes, abstract classes and interfaces
can lead to powerful and flexible programs Reflection– Powerful for building infrastructure
Job interview question
You are given the assignment of creating a component that needs to know sales statistics of Lottery tickets. You know that there is a another component in the system, Sale Server, that handles the sale. You need real-time information. What would you suggest?
EXERCISE
Design Patterns Design pattern is a general solution to a common
problem in software design– Systematic approach for problems that reoccur in
software development– Not complete solution but starting point for design – Not code ready to use– Patterns have names and definitions– Built on common practices
Patterns should not be language dependant– However patterns apply for types of programming
languages
Next Design Patterns