l04 software design examples

56
HÖNNUN OG SMÍÐI HUGBÚNAÐAR 2015 L04 SOFTWARE DESIGN EXAMPLES

Upload: olafur-andri-ragnarsson

Post on 10-Jan-2017

571 views

Category:

Technology


0 download

TRANSCRIPT

HÖNNUN OG SMÍÐI HUGBÚNAÐAR 2015L04 SOFTWARE DESIGN EXAMPLES

Agenda

Generic ProgrammingReflectionSoftware Design PrinciplesSoftware Design in Action

GENERIC PROGAMMING

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▪ 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 PRINCIPLES

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

SOFTWARE DESIGN IN ACTION

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

Example from Head First Design Patterns

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

The Interface Design Principle (GoF)

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

The Composition Design Principle (GoF)

Favour composition over inheritance

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

Design pattern is a general solution to a common problem in software design

Fyrirlestur mánudaginn 31.08 er video fyrirlestur vegna ferðalaga

Next