Suunnittelumalli
Suunnittelumalli () on ohjelmistotekniikassa ohjelmistorakenteen käsitteelliset (abstraktit) avainkohdat määrittävä kuvaus toistensa kanssa yhteistoiminnassa olevista luokista ja olioista. Suunnittelumalli sisältää yleisellä tasolla esitetyn ratkaisun johonkin oliopohjaisen suunnittelussa esiintyvään tavanomaiseen tilanteeseen tai kohteeseen. Suunnittelumalli perustuu käytännön kokemukseen ratkaisun toimivuudesta tietyssä tilanteessa, ja sen käytöstä on pitkä kokemus. Suunnittelumallin tärkeimmät osat ovat ongelma, ongelmayhteys ja ratkaisu. Suunnittelumallia voidaan käyttää työvälineenä suunniteltaessa ohjelman konkreettista arkkitehtuuria.
Suunnittelumalli on yleiskäyttöinen, käytännössä toimiva, uudelleenkäytettävä ja oliosuuntautunut ohjelmointilähtökohta, jota aloitteleva ohjelmoija ei tunne. Suunnittelumalli voi myös koskea ohjelman suppeaa yksityiskohtaa. Suunnittelumallin määrittelyssä kerrotaan sen käyttökohde, käyttöä rajoittavat tekijät, mallin seuraukset ja sen vahvuudet ja heikkoudet. Suunnittelumallin käyttö edellyttää riittävät ominaisuudet omaavan oliokielen käyttöä (esimerkiksi C++). Paras keino ymmärtää ja omaksua suunnittelumalli on sen tutkiminen.
Suunnittelumallissa ei ole tärkeintä malli itse, vaan se suunnittelukokemus ja asiantuntemus, joka sitä käyttäen saadaan säilytettyä ja siirrettyä muille ohjelmoijille. Kerätty informaatio tulee esittää käytännönläheisessä, selkeässä ja järjestelmällisessä muodossa, jolloin malli antaa käytännön ohjelmointityöhön järjestetyn ja valmiin kokoelman tiettyihin tilanteisiin sopivia ratkaisuja. Suunnittelumalleja ei tule käyttää tilanteissa, joista niistä ei ole hyötyä.
Ohjelmistoarkkitehtuurin kannalta suunnittelumallit käsittelevät yleensä suhteellisen pieniä yksiköitä (mikroarkkitehtuuria), mutta suunnittelumalleja voidaan käyttää myös koko sovelluksen perusrakenteessa (makroarkkitehtuuri). Suunnittelumallien ideaa on sovellettu käänteisenä keräämällä ns. antisuunnittelumalleja, joissa esitetään virheellisiä suunnitteluratkaisuja. Antisuunnittelumallia voidaan käyttää tunnistamaan ohjelmarakenteen virheitä ja suositeltavan suunnittelumallin soveltamiseen virheen poistamiseksi.
Suunnittelumallin käyttö ohjelmistotekniikassa perustuu amerikkalaisen arkkitehdin Christopher Alexanderin esittämään ajatukseen (Alexander, C. & ym. (1977). "A Pattern Language". New York: Oxford University Press) siitä, että rakentaminen perustuu hyväksi havaittujen ratkaisumallien keräämiseen, oppimiseen ja toistamiseen. Eräät ohjelmistotekniikan tutkijat (Kent Beck, Jim Coplien, Erich Gamma, ym.) tutustuivat näihin ajatuksiin, ja ryhtyivät kehittämään niiden käyttöä ohjelmointitekniikan yhteydessä.
Vuoden 1994 elokuussa pidetty PLoP-konferenssin (Pattern Language of Programming) jälkeen aloitettiin useita projekteja suunnittelumallien löytämiseksi. Vuoden 1995 alussa Erich Gamma, Richard Helm, Ralph Johnson ja John Vlissides ("Gang of Four") julkaisivat "Design Patterns: Elements of Reusable Object-Oriented Software", jossa esitettiin 23 suunnittelumallia.
Aikaisemmin Kent Beck ja Ward Cunningham toivat suunnittelumallit ohjelmistosuunnitteluun vuoden 1987 OOPSLA-konferenssissa. Vaikka he käyttivätkin esittelemiään suunnittelumalleja olio-ohjelmoinnin suunnittelussa, eivät ne olleet oliosuunnittelumalleja sanan nykyisessä merkityksessä, vaan niitä voidaan pitää käytettävyysmalleina. Erich Gamma oli käsitellyt suunnittelumalleja vuonna 1991 julkaistussa väitöskirjassaan, ja häntä pidetään suunnittelumallien tärkeimpänä kehittäjänä.
Suunnittelumallia kuvataan yleensä sen perustiedoilla, jotka määrittelevät mallin ja kuvaavat sen toiminnan.Nämä perustiedot ovat nimi, ongelman kuvaus, ratkaisun kuvaus ja ratkaisun vaikutukset ohjelmistoon ja tietokoneen laitteisiin. Muita suunnittelumallista esitettäviä tietoja voivat olla mm. luokittelu, mallista käytettävät muut nimet, esimerkki käyttötilanteesta, soveltuvuus, rakenteen esittäminen kaaviolla, malliin kuuluvat luokat ja niiden välinen tehtävien jako (vastuut), luokkien väliset rajapinnat, toteutuksessa esiintyvät ongelmat (esim. ohjelmointikielen vaikutus), esimerkki mallin toteuttamisella ohjelmointikielellä, esimerkkejä käytöstä todellisissa ohjelmissa ja mallia muistuttavat muut mallit ja mallit, joiden kanssa mallia olisi hyvä käyttää.
Suunnittelumallin nimi kuvaa mallin sisältämän periaatteen lyhyesti ja yksiselitteisesti. Mallin nimen perusteella voidaan nopeasti hahmottaa käytetty rakenne, sen tuottama hyöty ja siihen liittyvät rajoitukset. Mallin nimi auttaa ohjelmiston suunnittelemaan ajattelemaan ohjelmistorakennetta yleisellä (abstraktilla) tasolla, ja sen käyttö voi helpottaa suunnittelijoiden välistä keskustelua. Suunnittelumallin nimen tulisi olla osa suunnittelijan ammattisanastoa, mutta tilannetta on vaikeuttanut mm. se, että sama suunnittelumalli on nimetty eri nimillä tai käytännössä samat suunnittelumallit on nimetty eri nimillä. Samaa nimeä voidaan myös käyttää eri suunnittelumalleille.
Ongelma (Problem) kuvaa ohjelmoinnissa esiintyvää tavanomaista tilannetta, jonka ratkaisemisessa suunnittelumalli on ollut hyödyksi. Ongelman kuvaus voi olla laaja arkkitehtuuriin liittyvä tai sitten suppeampi, esim. tietyn algoritmin kuvaus. Suunnittelumalli voi joskus sisältää ominaisuuksia, joiden vuoksi sitä ei ole tarkoituksenmukaista käyttää muissa kuin erityistilanteissa. Nämä erityistilanteet on kuvattu tässä osassa suunnittelumallin määrittelyä. Ongelman tulee ilmetä toistuvasti monenlaisissa ohjelmistoissa ja sen tulee olla yleisluontoinen (esim. ohjelmointikielestä riippumaton). Muut kuin arkkitehtuuri- tai yksityiskohtaiseen suunnitteluun liittyvät ongelmat rajataan pois.
Ongelma esittää tilanteen, jossa mallia voidaan soveltaa. Ongelman kuvaus esitetään tarkasti identifioituna, mikä helpottaa käyttöalueen määritystä. Kuvaus voi myös esittää jonkin tyypillisen joustamattoman rakenteen, jota on parannettava. Suunnittelumallia ei ole syytä käyttää ellei ongelman kuvaus vastaa toteutettavassa ohjelmistossa esiintyvää ongelmatilannetta. Yleisesti voidaan todeta, että suunnittelumallien tehokas soveltaminen vaatii huolellista pohdintaa, sillä mallien soveltaminen voidaan tehdä vain suppeasti määritellyllä ongelma-alueella. Joskus ongelman kuvaus sisältääkin listan ehdoista joiden tulee täyttyä ennen kuin on hyödyllistä soveltaa suunnittelumallia.
Ongelmayhteys (Context) kuvaa sen kokonaisuuden, jossa ongelma ilmenee, ja se kertoo sen, missä tilanteissa suunnittelumallia voidaan käyttää. Ongelmayhteys määrittää lisäksi ratkaisulle asetettavia vaatimuksia ja niitä ohjelman laatuominaisuuksia, joita ratkaisun tulisi parantaa. Usein ongelma ja ongelmayhteys esitetään yhdessä, ja niitä havainnollistetaan esimerkeillä.
Ratkaisu (Solution) kuvaa mahdollisen ohjelmointirakenteen ja sen osat (esim. luokat, oliot, algoritmit), osien väliset suhteet ja niiden välisen vuorovaikutuksen (yleensä funktiokutsut) yleisellä tasolla. Ratkaisun antamia ohjelmoinnin suuntaviivoja on käytettävä käsitteellisenä runkona laadittaessa käytännön ratkaisua käsillä olevaan ohjelmointiongelmaan. Ohjelmistosuunnittelija arvioi tapauskohtaisesti sen, miten mallin ratkaisu sopii kyseessä olevaan tilanteeseen. Ratkaisun tulee olla sovellettavissa yleisesti ohjelmoinnissa, ja se tulee pystyä esittämään yleisti käytössä olevalla mallinnuskielellä (esim. UML). Ratkaisun yleiskäyttöisyydestä voi seurata se, että ohjelmiston laatuominaisuudet (esim. nopeus) heikkenee.
Ratkaisu on suunnittelumallin tärkein asia, ja se esitetään usein staattisena rakenteena (esim. UML:n luokkakaavio) jota täydennetään dynaamisen vuorovaikutuksen kaaviolla (esim. UML:n sekvenssikaavio). Kuvausta voidaan täydentää pseudokoodikuvauksella, joka kuvaa ohjelman kulun vaihe vaiheelta.
Ratkaisun tehtävänä on muodostaa yleinen kuvaus ongelman ratkaisusta. Ratkaisu kuvaa toteutuksessa käytettävät luokat, rajapinnat ja oliot, sekä niiden suhteet yleisellä tasolla. Vaikka ratkaisun rakenne esitetään yleensä UML-kaaviolla tai jollain muulla oliorakennetta kuvaavalla yleisesti tunnetulla kuvaustavalla (notaatio), ei ratkaisu kuvaa mitään erityistä tilannetta vaan yleisen tavan ratkaisulle. Tosin yksinkertainen esimerkki helpottaa ratkaisun toteutustavan ymmärtämistä. Ratkaisussa ei yleensä oteta kantaa käytettävään ohjelmointikieleen, mutta esimerkiksi moniperinnän puuttuminen osasta oliokieliä saattaa hankaloittaa ratkaisun toteuttamista. Yleisesti suunnittelumalleissa ei käytetä jonkin tietyn kielen erityisominaisuuksia ongelman ratkaisuun.
Seuraukset kuvaa mallin vaikutusta ohjelman sisäiseen ja ulkoiseen toimintaan, sekä sen käytöstä seuraavia hyviä ja huonoja seikkoja. Ohjelmistojen toiminnan kannalta tärkeitä seurauksia ovat mm. muisti ja suoritusaika ja ohjelmiston uudelleenkäyttö. Ohjelmiston uudelleenkäytön kannalta tärkeitä seurauksia ovat mm. käytetyn mallin vaikutus ohjelman laajennettavuuteen, muunneltavuuteen ja siirrettävyyteen. Mikään suunnittelumalli ei tuota joka suhteessa parasta ratkaisua, vaan kukin niistä optimoi tietyt ohjelman laatuominaisuudet ja heikentää muita. Seurausten kuvaaminen auttaa suunnittelijaa arvioimaan sitä, miten malli soveltuu käsillä olevaan suunnittelutilanteeseen. Seurauksista kertominen helpottaa suunnittelumallin soveltamista käytännön ohjelmistotyössä.
Toteutusnäkökulma kertoo käytännön ohjelmoinnissa esiintyvien tilanteiden ratkaisemisesta, esimerkiksi kertomalla mallin käytöstä eri ohjelmointikieliä käytettäessä. Toteutusnäkökulma on pidettävä erillään suunnittelumallin esittämästä teoreettisesta ajattelutavasta. Suunnittelumallin käytöstä voidaan antaa esimerkki todellisen järjestelmän toteutuksessa tai ohjelmointikielikohtaisena.
Suunnittelumallit luokitellaan yleensä sen tarkoituksen (luonti, rakenne, käyttäytyminen) ja sen kohteen (luokka, olio) perusteella. Mallit voidaan luokitella lisäksi myös sen mukaan, mitä malleja käytetään yleensä toistensa kanssa, mitkä mallit ovat toistensa vaihtoehtoja tai rakenteeltaan toisiaan vastaavia. Mallien luokittelun tarkoituksena on jäsentää ohjelmistoa käsitteellisiä lähestymistapoja (abstraktiotaso) kuvaavat mallit toistensa suhteen ja nopeuttaa mallien oppimista.
Luontimalli on suunnittelumalli, jolla ohjelmassa toimivan olion rakentaminen esitetään käsitteellisellä tasolla. Luontimalli peittää konkreettisesti käytettävien tuotantoluokkien näkyvyyden niitä käyttäviltä luokilta ja sen, miten tuotantoluokkia luodaan ja yhdistellään toisiinsa, eli tuotantoluokkia käyttävä tilaajaohjelma tuntee niistä vain niiden abstraktissa luokassa esitettävän rajapinnan. Rajapinnan käyttö mahdollistaa sen, että tuotantoluokkia ja niiden välisiä suhteita on helppo muuttaa ilman että sillä olisi vaikutusta luokkia tilaavan ohjelman toimintaan. Luontimalli kuvaa olioiden luomisprosessin, eli sen, kuinka, koska ja mitä olioita luodaan, ja huolehtivat luokkien ja olioiden asetusten konfiguroinnista.
Luontimalli on suunnittelumalli, jossa monimutkainen toiminnallisuus toteutetaan yhdistämällä useita eri toiminnallisuuksia. Luontimallit kätkevät tiedon siitä, mitä luokkia toiminnallisuuden toteuttamisessa käytetään ja miten näitä luokkia käytetään, luodaan ja liitetään toisiinsa.
Epäkonkreettinen tehdas (Absract Factory, Kit) on olion luontimalli, jossa konkreettisten luokkien olioryhmä (-perhe) luodaan luokasta jolla itsellään ei ole konkreettista ilmentymää (abstrakti luokka). EKT on rajapintaluokka, joka yhdistää toisiinsa saman tyyppisiä oliota.
EKT:tä voidaan käyttää ohjelman rakenteen mallina esim. käyttöliittymän toteutukseen eri alustoilla seuraavasti: Sovellusta käytetään eri käyttöliittymässä, jolloin käyttöliittymän rakentamistyökalun tulee tukea erilaisia käyttöliittymästandardeja. Käyttöliittymää luotaessa sovellus kutsuu abstraktin luokan (esim. UITehdas) funktiota (esim. luoIkkuna(), luoVierityspalkki(), luoPainonappi), joka edelleen kutsuu kyseisen ohjelmaympäristön konkreettista luokkaa, joka toteuttaa tarvittavat toiminnallisuudet.
EKT toteutetaan usein tehdasmenetelmällä, ja toteutuksessa voidaan käyttää myös prototyyppimallia. Abstraktin tehtaan alaluokka konkreettinen tehdas on tavallisesti ainokainen (luokasta luodaan vain yksi ilmentymä).
Rakentajarajapinta (Builder) on olion luontimalli, jossa erotetaan toisistaan olion esitysmuoto ja sen luomisprosessi. Tämän vuoksi sama prosessi voi tuottaa erilaisia olioita. Abstrakti rakentaja on abstrakti rajapintaluokka, joka luo konkreettisen rakentajaluokan osat. Rakentajaluokka toteuttaa halutut toiminnallisuudet (tuotteet). 
Rakentajaa voidaan käyttää ohjelman rakenteen mallina esim. muunnettaessa RTF-muotoista tekstiä muihin tekstiformaatteihin (esim. ASCII, muotoiltu teksti, jota ei voida muokata, muotoiltu teksti, jota voidaan muokata). RTFLukija (pääohjelma) kutsuu abstraktin rakentajan (TekstiKonvertoija), joka kutsuu edelleen konkreettisen rakentajan (ASCIIKonvertoija, TekstiKonvertoija, TekstiMuokkausKonvertoija) pääohjelman funktiokutsun sisältämän tiedon mukaan. Konkreettinen rakentaja määrittelee tuotteen kokoamisen prosessin ja kokoaa tuotteen sisäisen esitysmuodon.
Rakentajarajapinta muistuttaa epäkonkreettista tehdasta siinä, että molemmilla voidaan toteuttaa monimutkaisia toiminnallisuuksia. Mallit eroavat toisistaan siinä, että epäkonkreettinen tehdas palauttaa pyydetyn tuotteen välittömästi, kun taas rakentajarajapinta valmistaa tuotteen vaiheittain ja palauttaa sen prosessin viimeisenä vaiheena. Rakentajarajapintaa käytetään usein rekursiokoosteen kokoamiseen.
Tehdasfunktio (Factory Method, Virtual Constructor) on luokan luontimalli, jossa käytetään abstraktia funktiokutsua. Olion kutsumuoto on määritelty, ja luokan ilmentymän luominen on aliluokan tehtävä. Tehdasfunktiomallissa abstrakti luokka kapseloi konkreettisen luokan tarvitsemat tiedot ja välittää ne konkreettiselle tuotantoluokalle. Tehdasfunktiota voidaan käyttää ohjelman rakenteen mallina esim. sovelluksessa, joka tuo käyttäjän muokattavaksi useita dokumentteja.
Prototyyppirajapinta (Prototype) on olion luontimalli, jossa olion määrittely suoritetaan abstraktilla prototyyppiluokalla. Olio luodaan prototyyppiluokkaa kutsumalla ja luomalla siitä kopioita (kloonaus). Kopioiden ominaisuuksia voidaan muokata parametreilla, jolloin voidaan vähentää luokkien määrää.
Ainokainen (Singleton) on olion luontimalli, jossa luokasta luodaan täsmälleen yksi konkreettinen ilmentymä. Ilmentymään pääsy on globaali.
Rakennemalli on suunnittelumalli, joka kuvaa luokkia (ja olioita) ja niiden yhdistelyä suuremmiksi rakenteiksi. Rakennemalli kuvaa tavan, jolla luokkia ja olioita käytetään laajoissa rakenteissa. Rakennemalli esittää rajapinnat ja toteutuksen toisistaan erotettuina.
Sovitin (Adapter, Wrapper) on luokan tai olion rakennemalli, jossa kaksi toisiinsa sopimatonta rajapintaa liitetään toisiinsa käyttäen rajapintaluokkaa.
Silta (Bridge, Handle, Body) on ohjelmiston rakennemalli, jossa sovellukseen liitetty abstrakti rajapintaluokka kutsuu haluamansa toiminnallisuuden abstraktilta toiminnallisuuden rajapintaluokalta. Nämä kaksi rajapintaa muodostavat sillan, ja molempia rajapintoja voidaan vapaasti muunnella.
Koosteensa sisältävä kooste (rekursiokooste, Composite) on ohjelmiston rakennemalli, jossa yksi koosteolion rakentava abstrakti luokka käsittelee kyseistä koostetta samalla tavalla ja samanaikaisesti konkreettisten aliluokkien olioiden kanssa. Ohjelma käsittelee kaikkia itsensä sisältävän koosteen osia samalla tavalla.
Kuorruttaja (Decorator, Wrapper) on suunnittelumalli, jossa oliolle (ei koko luokalle) lisätään toiminnallisuutta (vastuita) ajon aikana (dynaamisesti) käyttämällä abstraktia rajapintaluokkaa, jonka alaluokat toteuttavat toiminnallisuuden. Kuorruttaminen on joustava vaihtoehto perinnälle.
Julkisivu (Facade) on ohjelmiston rakennemalli, jossa julkisivu-luokka tarjoaa yhden yhtenäisen rajapinnan alijärjestelmäluokkien rajapintojen joukolle ja niiden keskeisille palveluille. Julkisivu vähentää alijärjestelmien riippuvuuksia ja niiden välistä kommunikaatiota ja helpottaa alijärjestelmän käyttöä.
Hiutale (Flyweight) on ohjelmiston rakennemalli, jossa yhteiskäyttöistä oliota käytetään samanaikaisesti useissa eri yhteyksissä. Hiutale käyttäytyy jokaisessa käyttöyhteydessään itsenäisesti. Hiutaleessa olion sisäinen ja ulkoinen tila on erotettu toisistaan, sisäinen tila on tallentuneena hiutaleeseen, ja ulkoinen tila vaihtelee tilanteen mukaan ja riippuu asiayhteydestä.
Edustaja (Proxy, Surrogate) on ohjelmiston rakennemalli, jossa olioille luodaan korvike (tai paikan pitäjä) käyttäen abstraktia rajapintaluokkaa, jonka alaluokka konkreettinen Edustaja-luokka on. Edustaja-luokka kontrolloi olioon kohdistuvia pyyntöjä.
Käyttäytymismalli kuvaa ohjelman kulun vaihe vaiheelta (algoritmi), olioiden tehtävät (vastuut) ja olioiden suhteet toisiinsa ja niiden välisen yhteistyön (vuorovaikutus). Käyttäytymismalli kuvaa lisäksi ohjelmiston staattisen rakenteen (luokat). Käyttäytymismalli voi olla luokkiin perustuva (mm. operaatiorunko- ja tulkkimalli), olioihin perustuva (mm. tarkkailija-, vastuuketju- ja välittäjämalli) tai toiminnallisuuden kapselointi olioon (mm. iteraatio-, komento-, strategia-, tila- ja vierailijamalli). Käyttäytymismalli kuvaa olioiden välisen ohjelman suorituksen aikana tapahtuvan dynaamisen vuorovaikutuksen
Yleisfunktio (Template Method) perustuu toimintojen delegointiin luokille perintää käyttäen. Abstraktissa rajapintaluokassa määritellään tuotantoluokkien ne toiminnallisuudet, jotka ovat samat kaikissa alaluokissa. Tuotantoluokissa määritellään ne toiminnallisuudet, joiden käyttäytyminen voi vaihdella.
Tulkki (Interpreter) perustuu toimintojen delegointiin luokille perintää käyttäen. Laaditaan ohjelmointikieli, jolla voidaan määritellä haluttu toiminnallisuus. Ohjelmoidaan luokkia käyttäen tulkkausohjelma, joka kääntää kieliopin mukaiset käskyt toiminnallisuudeksi.
Tarkkailija (Observer) Perustuu toimintojen delegointiin olioille käyttäen koostamista. Olioiden välinen tiedonsiirto tapahtuu tarkkailijaa käyttäen, joka muuttaa olion tiedon niissä olioissa, jotka ovat siitä riippuvaisia (yksi-moneen-suhde). Klassinen esimerkki tarkkailijasta on MVC-malli (Model-View-Controller; Luokkamalli-Näkymä-Valvoja-malli).
Vastuuketju (Chain of Responsibility) perustuu toimintojen delegointiin olioille koostamista käyttäen. Olioiden välinen tiedonsiirto perustuu pyynnön mahdollisesti käsittelevien olioiden (kandidaattioliot) muodostamaan ketjuun, jossa pyyntö käsitellään siinä oliossa, joka voi toteuttaa pyynnön. Pyynnön vastaanottava (käsittelevä) olio ei ole sidottu pyynnön lähettäneeseen olioon.
Välittäjä (Mediator) perustuu toimintojen delegointiin olioille koostamista käyttäen. Eri olioiden välinen tiedonsiirto tapahtuu abstraktia kapseloitua välittäjäoliota käyttäen eli vuorovaikutuksessa olevat oliot eivät voi viitata toisiinsa, edistää olioiden löyhää sidontaa.
Iteraatio (Iterator) perustuu toiminnallisuuden kapselointiin olioon ja funktioiden kutsumiseen tarpeen mukaan. Esimerkiksi tietorakenteen läpikäymiseen peräkkäisjärjestyksessä käytettävä toiminnallisuus kapseloidaan olioon.
Komento (Command) perustuu kutsun kapselointiin abstraktiin olioon ja funktioiden kutsumiseen tarpeen mukaan tätä oliorajapintaa käyttäen.
Muisto (Memento) perustuu olion sisäisen tilan kapselointiin. Olion sisäinen tila kapseloidaan muisto-olioon, jonka tietoihin on pääsy vain tiedon lähdeoliolla.
Strategia (Strategy) perustuu olion ohjelma-algoritmien kapselointiin tuotanto-olioihin, joista muodostuu tuotanto-olioperhe. Abstrakti strategiaolio ohjaa pyynnön tuotanto-oliolle.
Tila (State) Perustuu olion tilan (ja tilaan liittyvän vaihtuvan toiminnallisuuden) kapselointiin abstraktin olion valitsemaan tuotanto-olioon. Kun a.oliota kutsutaan, se valitsee sen hetkisen tilansa mukaisen toiminnallisuuden toteuttavan konkreettisen olion.
Vierailija (Visitor) Perustuu kutsuvien luokkien yhtäpitävän toiminnallisuuden kapselointiin tuotantoluokkaan ja funktioiden kutsumiseen tarpeen mukaan abstraktia rajapintaluokkaa käyttäen. Kutsuvien luokkien toiminnallisuutta voidaan lisätä ilman niiden luokkarakenteen muuttamista tuotantoluokkia lisäämällä.
Suunnittelumalleilla ja kehyksillä on läheinen yhteys, koska molempien tarkoituksena on tavallisesti lisätä ohjelmiston joustavuutta ja siirrettävyyttä. Suunnittelumalleja voidaan käyttää myös kehysten dokumentointiin perusteltaessa sitä, miksi valittuun suunnitteluratkaisuun on päädytty.