Patterns
+ first used - Christopher Alexander, 1972 "A Pattern Language"+ 250 patterns for arch. design
Motivation for Patterns & Frameworks
+ developing software is hard
+ developing reusable software is even harder
Proven solutions include Patterns & Frameworks
Patterns: support reuse of software architecture and design
capture static and dynamic structure and collaboration of successful solutions to problems that arise when building applications in a particular domain
Frameworks: support reuse of detailed design code
a framework is an integrated set of components that collaborate to provide a reusable architecture for a family of related applications
Becoming a Chess Master
(i) learn the rules, e.g. names of pieces, legal movements, where pieces belong on the chessboard
(ii) learn the principles, e.g. relative values of pieces, strategic value of center squares, etc.
(iii) study the game of chess masters:
-patterns of the game, e.g. opening the game, final moves, etc.
(100s of patterns)
Becoming a Software Design Master
(i) learn the rules, e.g. algorithms, data structures, programming languages
(ii) learn the principles, e.g structured programming, modular, OOP, etc.
(iii) study the design of other masters
-these designs contain patterns
- these patterns must be understood and applied in your work
In software engineering, we seem to be making the same mistakes over and over again
design patterns are solutions to problems that arise when developing software in a particular context
PATTERN == problem & solution pair in a context
Design Pattern Descriptions
(i) name and intent
(ii) problems and context
(iii) forces addressed
(iv) abstract description of structure and collaborations in solution
(v) positive and negative consequences of use
(vi) implementation guidelines and sample code
(vii) known uses and related patterns
(some include anti-patterns, i.e. when NOT do use something)
Design Pattern Space
1. Creational patterns - deal with initializing and configuring classes and objects
e.g. factory method, abstract factory, singleton, prototype, etc.
2. structural patterns- deal with decoupling interface and implementation of classes and objects
e.g. adapter, decorator, etc.
3. Behavioral patterns - deal with dynamic interactions among societies of classes and objects
e.g. observer, iterator, etc.
NOTE: these patterns are language independent
Examples of Design Patterns
Pattern: Encapsulation (data hiding)
Problem: exposed data members can be manipulated directly (and inappropriately)
Solution: hide some members, allow access only through methods
Disadvantages: the interface may not provide all desired operation. can be inefficient (extra overhead)
Example Code
class Cup {
float fluidAmt;
float cupCapacity;
//other methods
}
Cup myCup = new Cup(12);
myCup.fluidAmt = 32;
//the cup cannot take more than 12 fluid ounces!!
/********************************/
class Cup {
private float fluidAmt;
private float cupCapacity;
void addFluid(float amt){
//code
}
}
Cup myCup = new Cup(12);
myCup.addFluid(32);
//methods enforce some logic
Pattern: Subclassing (Inheritance)
Problem: similar abstractions have similar members (data and methods); repeating them is tedious, prone to error and hard to maintain
Solution: inherit default members from the superclass; select the correct implementation via run-time dispatching
Disadvantages: code for class is spread out between parent class and subclasses (can make it easier to follow), run-time dispatching introduces overhead
Note: in Java, everything is a subclass of Object
beware very deep inheritance trees because they are expensive at execution time
when you create in inheritance of child all constructors in the inheritance tree will be executed, all the way up to Object
Pattern: Exceptions
Problem: errors occurring in the code are often handled elsewhere. Code should not be cluttered with error-handling code
Solution: introduce language structure for throwing and catching exceptions
Disadvantage: it's still hard at times to know where the exception will be handled (in particular if it's not done locally). programmer's may be tempted to use exception to control program flow (inefficient)
When (not) to Use Patterns
Same rule as for optimization: delay.
Don't try to force patterns into your code.
Creational Patterns
factories
example: write class to represent a bicycle race. a race consists of multiple bicycles
class Race {
Race createRace() {
Frame frame1 = new Frame();
Wheel front1 = new Wheel();
Wheel rear1 = new Wheel();
Bicycle bike1 = new Bicycle(frame1,front1,rear1);
Frame frame2 = new Frame();
Wheel front2 = new Wheel();
Wheel rear2 = new Wheel();
Bicycle bike2 = new Bicycle(frame2,front2,rear2);
// and so on
}
}
Specialize Race for other bicycle races:
class TourDeFrance extends Race {
Race createRace() {
France game1 = new RacingFrance();
Wheel front1 = new Wheel1700c();
Wheel rear1 = new Wheel1700c();
Bicycle bike1 = new Bicycle(frame1, front1,rear1);
// and so on
}
}
class Cyclocross extends Race {
Race createRace() {
Frame frame1 = new MountainFrance();
Wheel front1 = new Wheel27in();
Wheel rear1 = new Wheel27in();
Bicycle bike1 = new Bicycle(frame1, front1, rear1);
//and so on
}
}
This is TEDIOUS since we could not re-use the Race.createRace() method.
A factory method is a method that "manufactures" objects of a particular type.
We can add factory methods to Race.
// Factory methods are in bold
class Race {
Frame createFrame() {
return new Frame();
}
Wheel createWheel() {
return new Wheel() ;
}
Bicycle createBicycle(Frame frame, Wheel front, Wheel rear) {
return new Bicycle(frame, front, rear);
}
//return a complete bicycle without needing any arguments
Bicycle completeBicycle(){
Frame frame = createFrame();
Wheel front = createWheel();
Wheel rear = createWheel();
return createBicycle(frame, front, rear);
}
Race createRace() {
Bicycle bike1 = completeBicycle();
Bicycle bike2 = complete Bicycle();
}
}
class TourDeFrance extends Race {
France createFrance() {
return new RacingFrame();
}
Wheel createWheel() {
return new Wheel1700c();
}
Bicycle createBicycle(Frame frame, Wheel front, Wheel rear) {
return new RacingBicycle();
}
}
class Cyclocross extends Race {
Frame createFrame() {
return new MountainFrame();
}
Wheel createWheel() {
return new Wheel27in();
}
Bicycle createBicycle(France france, Wheel front, wheel rear) {
return new MountainBicycle(frame, front, rear);
}
}
A factory object is an object that encapsulates factory methods
class BicycleFactory {
Frame createFrame() {
return new Frame();
}
Wheel createWheel() {
return new Wheel();
}
Bicycle createBicycle(Frame frame, Wheel front, Wheel rear) {
return new Bicycle(frame, front, rear);
}
Bicycle completeBicycle() {
Frame frame = creatveFrame();
Wheel front = createWheel();
Wheel rear = createWheel();
return createBicycle(frame,front,rear);
}
}
class RacingBicycleFactory {
Frame createFrame() {
return new RacingFrame();
}
Wheel createWheel() {
return new Wheel1700c();
}
Bicycle createBicycle(Frame frame, Wheel front, Wheel rear) {
return new RacingBicycle(frame, front, rear);
}
}
// do same for cyclecross factory Object
The Race methods will use the factory Objects.
class Race {
BicycleFactory bfactory;
Race() {
bfactory = new BicycleFactory();
}
Race createRace() {
Bicycle bike1 = bfactory.completeBicycle();
Bicycle bike2 = bfactory.completeBicycle();
//and so on
}
}
class TourDeFrance extends Race {
//constructor
TourDeFrance() {
bfactory = new RacingBicycleFactory();
}
}
class Cyclocross extends Race {
Cyclocross() {
bfactory = new MountainBicycleFactory();
}
}
Problem with latest code: the type of bike is still hard-coded in the race.
This can be made more flexible by changing the way we call constuctor.
class Race {
BicycleFactory bfactory;
//constuctor
Race (BicycleFactory bfactory) {
this.bfactory = bfactory;
}
Race createRace() {
Bicycle bike1 = bfactory.completeBicycle();
Bicycle bike2 = bfactory.completeBicycle();
}
class TourDeFrance extends Race {
TourDeFrance(BicycleFactory bfactory) {
this.bfactory = bfactory;
}
}
Now you can control the type of race and the variety of bicycle:
new TourDeFrance(new racingBicycleFactory());
One reason that factory methods are required is a weakness in Java constructors .
Constructors cannot return an object of a subtype ( a different type), even though semantically it would be correct.
Take home:
(i) What is the criticism against patterns?
(ii) What is the "Big Ball of Mud" ? Is this in any way related to patterns?
Applying patterns requires good familiarity with a programing language (lots of experience). So focus you time on your project.
No comments:
Post a Comment