Ohjelmistotuotannon menetelmätSyksy 2003
Design Patterns(Sami Jantunen, LTY/TITE)
Ohjelma1. Design Patterneista Yleisesti
Historiatietoa Määrittely Ominaisuuksia Design Patternien kuvaustavat Patterntyypit Patternkieli, systeemi, kataloogi Design patternien käyttö oliopohjaisen järjestelmän
kehityksessä AntiPattern
2. Esimerkkejä Design Patterneista Creational Patterns Structural Patterns Behavioral Patterns
Luettavaa
Design PatternsElements of Reusable Object-Oriented
Software
byErich Gamma,
Richard Helm, Ralph Johnson, and John Vlissides
(The Gang of Four).
Historiatietoa Arkkitehti Christopher Alexanderin kirjoitukset 1970-luvun
lopulla. “ajattomien” hyväksi todettuja ratkaisuja etsintä talojen
suunnittelussa termi Pattern Pattern ajattelun omaksuminen ohjelmistotuotannon alalla
1980-luvun lopussa Kent Beck and Ward Cunningham, Textronix, OOPSLA'87
(käytti Alexander's "pattern" ideaa Smalltalkin GUI suunnittelussa)
Erich Gamma, Ph. D. väitöskirja, 1988-1991 James Coplien, Advanced C++ Idioms kirja, 1989-1991 Gamma, Helm, Johnson, Vlissides ("Gang of Four“ - GoF)("Gang of Four“ - GoF)
Design Patterns: Elements of Reusable Object-Oriented Software, 1991-1994
Design Patterns määrittely … a fully realized form, original, or model accepted or proposed
for imitation…[dictionary]
... describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice [Alexander]
… the abstraction from a concrete form which keeps recurring in specific non-arbitrary contexts [Riehle]
…both a thing and the instructions for making the thing [Coplien]
...a literary format for capturing the wisdom and experience of expert designers, and communicating it to novices
Patternien ominaisuuksiaPatternit… tarjoaa yhteisen sanaston kuvaamaan
ratkaisumalleja tiettyihin ongelmiin tehostaa kommunikaatiota monimutkaisten
järjestelmien suunnittelussa auttaa arkkitehtuurin dokumentoinnissa
Patternit eivät... tarjoa eksaktia ratkaisua ratkaise kaikkia suunnitteluongelmia rajoitu pelkästään oliokeskeiseen suunnittelutyöhön
Esimerkki: The Courtyard Pattern – Christopher Alexander
“Consider the forces at work in a courtyard. Most fundamental of all, people seek
some kind of private outdoor space, where they can sit under the sky, see the
stars, enjoy the sun, perhaps plant flowers. This is obvious. But there are more
subtle forces too. For instance, when a courtyard is too tightly enclosed, has no
view out, people feel uncomfortable, and tend to stay away … they need to see
out into some larger and more distant space. Or again, people are creatures of
habit. If they pass in and out of the courtyard, every day, in the course of their
normal lives, the courtyard becomes familiar, a natural place to go … and it is
used. But a courtyard with only one way in, a place you only go when you “want”
to go there, is an unfamiliar place, tends to stay unused … people go more often
to places which are familiar. Or again, there is a certain abruptness about
suddenly stepping out, from the inside, directly to the outside … it is subtle, but
enough to inhibit you. If there is a transitional space, a porch or a veranda, under
cover, but open to the air, this is psychologically half way between indoors and
outdoors, and makes it much easier, more simple, to take each of the smaller
steps that brings you out into the courtyard”
The Courtyard Pattern jatkoa…(johtopäätös)
“When a courtyard has a view out to a larger space has crossing
paths from different rooms has a veranda or a porch these forces
can resolve themselves. The view out makes it comfortable, the
crossing paths help generate a sense of habit there, the porch
makes it easier to go out more often … and gradually the courtyard
becomes a pleasant customary place to be.”
Patternin sisältö
Pattern
Solution
Problem
Context
a design situation giving rise to a design problem
a form or rule that can be applied to resolve these forces
a set of forces occuring in that context
“Courtyard” esimerkki… Identifioi patternin Kuvasi asiat mitä tulisi tavoitella Kuvasi miten tavoite voitaisiin saavuttaa Kertoi voimista, mitkä saattaisi vahingoittaa toivottua
tavoitetta
Patternin rakenne Alexanderin tyyli (canonical form)
Namemeaningful name
Problemthe statement of the problem
Contexta situation giving rise to a problem
Forcesa description of relevant forces and constraints
Solution proven solution to the problem
Examples sample applications of the pattern
Resulting context (force resolution)the state of the system after pattern has been applied
Rationale explanation of steps or rules in the pattern
Related patterns static and dynamic relationship
Known useoccurrence of the pattern and its application within existing system
Patternin rakenne GoF tyyli
Pattern name and classification Intent
what does pattern do / when the solution works
Also known as other known names of pattern (if any)
Motivation the design problem / how class and object structures solve the problem
Applicability situations where pattern can be applied
Structure a graphical representation of classes in the pattern
Participants the classes/objects participating
and their responsibilitiesCollaborations
of the participants to carry out responsibilitiesConsequences
trade-offs, concerns Implementation
hints, techniquesSample code
code fragment showing possible implementationKnown uses
patterns found in real systemsRelated patterns
closely related patterns
Pattern-tyyppejä
Creational Patterns tekee järjestelmistä riippumattomampia
olioiden luontitavasta.Structural Patterns
Luokkien ja olioiden kokoaminen suuremmiksi rakenteiksi.
Behavioral Patterns Algoritmien ja olioiden välisten vastuiden
määrittely.
Pattern catalogs and systems
[Buschmann, POSA][Buschmann, POSA] pattern catalog
…a collection of related patterns, where patterns are subdivided into small number of broad categories…
pattern system…a cohesive set of related patterns, which work
together to support the construction and evolution of hole architectures...
Design pattern luettelo (Gang of Four)
Purpose
Creational Structural Behavioral
Class Factory Method Adapter Interperter
Scope
Object
Abstract Factory
Builder Prototype Singleton
Adapter Bridge Composite Decorator Facade Flyweight Proxy
Chain of Responsibility Command Iterator Mediator Momento Observer State Strategy Vistor
Patterneita kuvattu esim: http://pages.cpsc.ucalgary.ca/~kremer/patterns/
Patternien käyttö luokkakaaviossa-Vaikeudet ja riskit
Patternit eivät ole patenttiratkaisu: Älä käytä patterneja suin päin. Patternien
soveltaminen voi johtaa huonoihin ratkaisuihin.
Ymmärrä aina syvällisesti seikat mitkä pitää ratkaista ja mikä pattern ratkaisee kyseiset ongelmat
Pidä huolta, että perustelet jokaisen suunnittelupäätöksen huolellisesti
AntiPattern AntiPattern kertoo kuinka ongelma ratkaistaan
huonosti Hyvä AntiPattern kertoo:
miksi huono ratkaisu näyttää houkuttelevalta miksi ratkaisu osoittautuu lopulta huonoksi mitä Patternia kannattaisi käyttää ongelman
ratkaisuun
“an anti-pattern is something that looks like a good idea, but which backfires badly when applied.” (Jim Coplien)
Antipatternesimerkki: ZeroMeansNull
Name: ZeroMeansNull Type: Design Category: AntiPattern Problem: Implementing an optional field. Forces: Laziness or optimism. Ignorance of nulls, e.g. "they're too inconvenient to
deal with". Using a storage implementation that doesn't support them. Supposed solution: Nobody will ever set this to all zeros, so let that represent
"omitted." Resulting context: When it really needs to be zero, it can't be. When you need to
convert from ints to some form of real, you can't reliably detect zero (RealNumbersAreNotEqual). You can forget to compare with zero in some cases, and let it through as a nonsense value. You're more likely to get an exception (e.g. NullPointerException in Java) if you use a proper null.
Example: Designer thinks "Nobody will ever be at latitude zero, longitude zero." User reports:"I hope you can help me! I'm trying to draw grid lines on the globe and for some reason one is always missing...."
Lisää antipatterneja: http://c2.com/cgi/wiki?AntiPatternsCatalog
Missä mennään?
1. Design Patterneista Yleisesti Historiatietoa Määrittely Ominaisuuksia Design Patternien kuvaustavat Patterntyypit Patternkieli, systeemi, kataloogi Design patternien käyttö oliopohjaisen järjestelmän
kehityksessä AntiPattern
2. Esimerkkejä Design Patterneista Creational Patterns Structural Patterns Behavioral Patterns
Esimerkki:TietokonepeliHaluaisimme luoda labyrintin tietokonepeliin…
Alustava ratkaisu:
Luokkien määrittely
MapSite-luokka on yhteinen abstrakti isäluokka kaikkiin labyrinttiin kuuluviin luokkiin.
Class MapSite {
public:
virtual void Enter() = 0;
};
Enter-metodin tarkoitus riippuu siitä mihin ollaan labyrintissä astumassa sisään
Jatkoa luokkien määrittelyyn...
Enum Direction {North, South, East, West};
Class Room : public MapSite {
public:
Room(int roomNo);
MapSite* Side(Direction) const;
void Set_side(Direction, MapSite*);
virtual void Enter() { //… }
private:
MapSite* _sides[4];
int _roomNo;
};
Jatkoa luokkien määrittelyyn...
Jokaisessa huoneessa on 0-4 seinää ja 0-4 ovea.
Class Wall : public MapSite {
public:
Wall();
virtual void Enter() { /… }
};
Jatkoa luokkien määrittelyyn...Jokainen ovi on kahden huoneen välissä:
class Door : public MapSite {
public:
Door(Room* = NULL, Room* = NULL);
virtual void Enter() { //… }
Room* Other_side_from(Room*);
private:
Room* _room1;
Room* _room2;
bool _isOpen;
};
Jatkoa luokkien määrittelyyn...
Maze (labyrintti) -luokka koostuu kokoelmasta huoneita:class Maze {
public:
Maze();
void Add_room(Room*);
Room* RoomNo(int) const;
private:
List rooms; //List of Room*
};
Labyrintin kokoaminen
Implementoidaan Maze_game –luokka joka luo labyrintin. Labyrintti voidaan luoda sarjalla operaatioita, missä olioita lisätään labyrinttiin yksi kerrallaan ja kytketään niitä sitten yhteen.
Esimerkki: Luodaan 2 hengen labyrintti
Maze* Maze_game::Create_maze () {
Maze* maze = new Maze;
Room* r1 = new Room(1);
Room* r2 = new Room(2);
Door* door = new Door(r1, r2);
maze->Add_room(r1);
maze->Add_room(r2);
r1->Set_side(North, new Wall);
r1->Set_side(East, door);
r1->Set_side(South, new Wall);
r1->Set_side(West, new Wall);
r2->Set_side(North, new Wall);
r2->Set_side(East, new Wall);
r2->Set_side(South, new Wall);
r2->Set_side(West, door);
return maze;
}
OngelmaJOUSTAMATTOMUUS
Labyrintti on kovakoodattu Labyrintin muuttaminen merkitsisi käytännössä uusiksi
ohjelmoimista
Labyrintin jatkokehitys…
Mitä jos haluttaisiin käyttää hyväksi vanhaa labyrinttiä ja jatkokehittää sitä seuraavilla luokilla:
Door_needing_spell – Ovi, joka sulkeutuu tai avautuu loitsun avulla.
Enchanted_room – Huone, jossa on epätavallisia esineitä.
Labyrintin uudelleenkäytön parantelu…Olemassa oleva koodi tulisi muuttaa sellaiseksi, että uuden tyyppisten olioiden luominen
tapahtuisi mahdollisimman pienin koodimuutoksin? Annetaan Create_maze:en parametrina olio, jonka tehtävänä on luoda huoneet, seinät ja ovet
Määritellään ensin Maze_factory –luokka, joka luo labyrintin osaset ajonaikana.
Class Maze_factory {public:
Maze_factory(); // the following are also called “virtual constructor”.
virtual Maze* Make_maze() const { return new Maze; }virtual Wall* Make_wall() const{ return new Wall; }virtual Room* Make_room(int n) const { return new Room(n); }virtual Door* Make_door(Room* r1, Room* r2) const { return new Door(r1, r2); }
};
Parannetaan Create_maze -metodia
Maze* Maze_game::Create_maze(Maze_factory& factory) { Maze* maze = factory.Make_maze(); Room* r1 = factory.Make_room(1); Room* r2 = factory.Make_room(2); Door* door = factory.Make_door(r1, r2);
maze->Add_room(r1); maze->Add_room(r2);r1->Set_side(North, factory.Make_wall());r1->Set_side(East, door);r1->Set_side(South, factory.Make_wall());r1->Set_side(West, factory.Make_wall());
r2->Set_side(North, factory.Make_wall());r2->Set_side(East, factory.Make_wall());r2->Set_side(South, factory.Make_wall() );r2->Set_side(West, door);
return maze;}
Ja palataan sitten parannellun labyrintin pariin….
Luodaan Enchanted_maze_factory –luokka perimällä se Maze_factory:sta.
Tämä luokka yliajaa jäsenfunktiot ja palauttaa erilaiset Room- Wall, … -oliot
Class Enchanted_maze_factory : public Maze_factory {public:
Enchanted_maze_factory ();
virtual Room* Make_room(int n) const {return new Enchanted_room(n, Cast_spell()); }
virtual Door* Make_door(Room* r1, Room* r2) const { return new Door_needing_spell(r1, r2);}
protected:Spell* Cast_spell() const;
};
Labyrintin rakentaminenMaze_game game;
Enchanted_maze_factory factory;
game.create_maze(factory);
Tällä tavalla voimme luoda minkälaisen labyrintin tahansa!
Lopputulos: Abstract Factory
Maze_factoryMaze_factory
Make_maze()Make_room()
Make_wall()
Make_door()
RoomRoom
Clientuses
usesDoorDoor
uses
Bombed_factoryBombed_factory
Make_wall() Make_room()
Enchanted_factoryEnchanted_factory
Make_room()Make_door()
Door_need_spell
Bombed_wall
Enchanted_roomRoom_with_bomb
create
createcreate
WallWall
uses
Abstract Factory Pattern
AbstractFactoryAbstractFactory
createProductA()createProductB()
ConcreteFactory1ConcreteFactory1
createProductA()createProductB()
ConcreteFactory2ConcreteFactory2
createProductA()createProductB()
AbstractProductAAbstractProductA
AbstractProductBAbstractProductB
ProductB1ProductB2
ProductA1ProductA2
ClientClientuses
uses
uses
create
create
Singleton Pattern
Konteksti: On hyvin tavallista että tietystä luokasta pitäisi olla
olemassa vain yksi instanssi (singleton) Ongelma:
Kuinka varmistat, että luokkaa ei missään tilanteessa luoda enemää kuin yksi olio?
Vahingoittavia voimia: public konstruktorin käyttö ei takaa, että olioita
tulee vain yksi. singleton instanssi pitää olla kaikkien halukkaiden
luokkien käytettävissä
Singleton Patternclassclass Singleton { Singleton {publicpublic:: staticstatic Singleton *get_instance(); Singleton *get_instance();protectedprotected:: Singleton(); Singleton();
Singleton( Singleton( constconst Singleton& s); Singleton& s);privateprivate:: staticstatic Singleton *instance; Singleton *instance;};};Singleton::instance = 0;Singleton::instance = 0;
Singleton *Singleton::get_instance() {Singleton *Singleton::get_instance() { ifif ( instance == 0 ) { ( instance == 0 ) { instance = instance = newnew Singleton; Singleton; } } returnreturn instance; instance;}}
Company
theCompany
Company «private»getInstance
if (theCompany==null) theCompany= new Company();
return theCompany;
«Singleton»
theInstance
getInstance
Esimerkki: Singleton patternin käyttö labyrintissäClass Maze_factory {public:
static Maze_factory* get_instance();//existing interface goes here…
protected:Maze_factory();Maze_factory(const Maze_factory& f);
private:static Maze_factory* instance;
};Maze_factory::instance = 0;Maze_factory* Maze_factory::get_instance(){
if (_instance == 0)_instance = new Maze_factory;
return _instance;}
Missä mennään?
1. Design Patterneista Yleisesti Historiatietoa Määrittely Ominaisuuksia Design Patternien kuvaustavat Patterntyypit Patternkieli, systeemi, kataloogi Design patternien käyttö oliopohjaisen järjestelmän
kehityksessä AntiPattern
2. Esimerkkejä Design Patterneista Creational Patterns Structural Patterns Behavioral Patterns
Adapter Pattern Konteksti
Olet rakentamassa perintähierarkiaa ja haluat käyttää siinä hyväksi jo olemassa olevaa luokkaa
Uudelleenkäytetty luokka on usein jo osa omaa perintähierarkiaa
Ongelma Kuinka voi käyttää polymorphismin etuja hyväksi kun
uudelleenkäyttää olemassa olevan luokan metodeja, jotka:
sisältävät halutun toiminnallisuuden mutta funktion nimikirjoitus (signature) ei ole sama
kuin muut hierarkiassa olevat metodit? Vahingoittavat voimat
Et halua tai saa käyttää moniperintää.
Adapter
«Adaptee»
adaptedMethod
«Superclass»
polymorphicMethod
«Adapter»
polymorphicMethod()
return adaptee.adaptedMethod();
{
}
Façade Pattern Konteksti
Sovellus sisältää usein useita monimutkaisia moduuleja Ohjelmoijan, joka käyttää moduuleja täytyy manipuloida useita
eri luokkia Ongelma
Kuinka voi yksinkertaistaa monimutkaisten moduulien käytettävyyttä?
Vahingoittavat voimat Ohjelmoijan on vaikea ymmärtää ja käyttää kokonaisia
alisysteemejä Jos useat eri sovelluksen luokista kutsuvat moduulin metodeita,
niin moduulin kohdistuvat muutokset pakottaa katselmoimaan uusiksi kaikki ne luokat jotka pakettia käyttävät.
Façade
Proxy Konteksti
On usein aikaavievää ja monimutkaista luoda raskaasta luokasta (heavyweight class) olioita
Tällaisen olion luomiseen liittyy monimutkainen luontimekanismi ja se aiheuttaa aikaviiveen
Ongelma Kuinka voisi vähentää tarvetta luoda instansseja
raskaista luokista? Vahingoittavat voimat
Kaikki oliot on oltava käytettävissä tarpeen mukaan Joillekin olioille on tärkeää olla olemassa koko
ohjelman ajon ajan
Proxy
Käyttötarkoituksia: Remote Proxy voi piilottaa tiedon siitä, että todellinen
olio onkin toisessa muistiavaruudessa object is in another address space.
Virtuaali Proxyt voi luoda resursseja syövät oliot tarpeen vaatiessa.
Protection proxy voi kontrolloida käyttöoikeuksia olioon.
Missä mennään?
1. Design Patterneista Yleisesti Historiatietoa Määrittely Ominaisuuksia Design Patternien kuvaustavat Patterntyypit Patternkieli, systeemi, kataloogi Design patternien käyttö oliopohjaisen järjestelmän
kehityksessä AntiPattern
2. Esimerkkejä Design Patterneista Creational Patterns Structural Patterns Behavioral Patterns
Chain of Responsibility
Tarkoitus: Välttää pyynnön lähettäjän ja vastaanottajan kytkemistä (coupling) tarjoamalla
useita vaihtoehtoisia olioita, jotka voivat hoitaa pyynnön. Pyynnön vastaanottajaoliot (handler) ketjutetaan ja pyyntöä kuljetetaan handlerilta toiselle kunnes jokin handlereista hoitaa sen.
Esimerkki: Käyttöliittymän context-sensitive help ominaisuus. Käyttäjä voi saada apua mistä
tahasa käyttöliittymän osiosta klikkaamalla kyseistä käyttöliittymän osaa. Jos tästä osasta ei ole ohjeita saatavilla, yleisempi ohje valitusta kontekstista esitetään.
Observer
Tarkoitus: Määrittelee one-to-many riippuvuuden olioiden välille siten, että kun yksi
olio muuttaa tilaansa kaikki siitä riippuvat oliot päivittyvät. Muuttoksen aiheuttava olio ei välttämättä tiedä muita muutettavia olioita
Observer -Esimerkkejä
WeatherViewer
Observers are notified when a new prediction is readyForecaster
Observable * ****** «interface»Observer
Iterator
Tarjoaa keinon päästä käsiksi aggregaatin hallinoimiin elementteihin ilman, että aggregaatin sisäinen toteutus paljastuu
Tarjoaa yhtenäinen rajapinta eri aggregaatti rakenteiden selailuun
esimerkki: Standard Template Library (STL) container iteraattorit.
Top Related