Programmering

Introduktion til designmønstre, del 1: Designmønsterhistorie og klassifikation

Der er udtalt adskillige strategier for at forenkle og reducere omkostningerne ved design af software, især inden for vedligeholdelsesområdet. At lære at identificere og arbejde med genanvendelige softwarekomponenter (lejlighedsvis kaldet software integrerede kredsløb) er en strategi. Brug af designmønstre er en anden.

Denne artikel lancerer en tredelt serie om designmønstre. I denne del introducerer jeg den konceptuelle ramme for designmønstre og gennemgår en demonstration af evaluering af et designmønster til en bestemt brugssag. Jeg vil også diskutere historien om designmønstre og antimønstre. Endelig klassificerer jeg og opsummerer de mest anvendte softwaredesignmønstre, der er blevet opdaget og dokumenteret gennem de sidste par årtier.

Hvad er et designmønster?

At designe genanvendelig objektorienteret software, der modellerer et eksisterende system, er virkelig udfordrende. En softwareudvikler skal faktorere systemets enheder i klasser, hvis offentlige grænseflader ikke er for komplekse, etablere relationer mellem klasser, udsætte arvshierarkier og mere. Da de fleste software forbliver i brug længe efter den blev skrevet, skal softwareudviklere også adressere de aktuelle applikationskrav, mens de holder deres kode og infrastruktur fleksibel nok til at imødekomme fremtidige behov.

Erfarne objektorienterede udviklere har opdaget, at softwaredesignmønstre letter kodning af stabile og robuste softwaresystemer. At genbruge disse designmønstre i stedet for konstant at udvikle nye løsninger fra bunden er effektivt, og det reducerer noget af risikoen for fejl. Hvert designmønster identificerer et tilbagevendende designproblem i en bestemt applikationskontekst og tilbyder derefter en generaliseret, genanvendelig løsning, der kan anvendes i forskellige applikationsscenarier.

"EN design mønster beskriver de klasser og interagerende objekter, der bruges til at løse et generelt designproblem i en bestemt sammenhæng. "

Nogle udviklere definerer en design mønster som en klassekodet enhed (såsom en sammenkædet liste eller bitvektor), mens andre siger, at et designmønster findes i hele applikationen eller delsystemet. Min opfattelse er, at en design mønster beskriver klasser og interagerende objekter, der bruges til at løse et generelt designproblem i en bestemt sammenhæng. Mere formelt er et designmønster specificeret som en beskrivelse, der består af fire grundlæggende elementer:

  1. EN navn der beskriver designmønsteret og giver os et ordforråd til at diskutere det
  2. EN problem der identificerer designproblemet, der skal løses sammen med den sammenhæng, hvor problemet opstår
  3. EN opløsning til problemet, som (i en software design mønster sammenhæng) skal identificere de klasser og objekter, der bidrager til designet sammen med deres forhold og andre faktorer
  4. En forklaring på konsekvenser at bruge designmønsteret

For at identificere det passende designmønster, der skal bruges, skal du først klart identificere det problem, du prøver at løse; det er her problem element i beskrivelsen af ​​designmønsteret er nyttigt. At vælge et designmønster frem for et andet involverer normalt også kompromiser, der kan påvirke en applikations eller systems fleksibilitet og fremtidige vedligeholdelse. Derfor er det vigtigt at forstå konsekvenser at bruge et givet designmønster, inden du begynder at implementere det.

Evaluering af et designmønster

Overvej opgaven med at designe en kompleks brugergrænseflade ved hjælp af knapper, tekstfelter og andre komponenter, der ikke er containere. Kompositdesignmønsteret betragter containere som komponenter, som lader os rede containere og deres komponenter (containere og ikke-containere) i andre containere og gøre det rekursivt. Hvis vi vælger ikke at bruge det sammensatte mønster, bliver vi nødt til at oprette mange specialiserede komponenter, der ikke er containere (en enkelt komponent, der f.eks. Kombinerer et kodeordstekstfelt og en loginknap), hvilket er sværere at opnå.

Efter at have overvejet dette forstår vi det problem, vi prøver at løse, og den løsning, der tilbydes af det sammensatte mønster. Men hvad er konsekvenserne af at bruge dette mønster?

Brug af komposit betyder, at dine klassehierarkier vil blande container- og ikke-container-komponenter. Enklere klienter behandler container- og ikke-container-komponenter ensartet. Og det bliver lettere at introducere nye slags komponenter i brugergrænsefladen. Komposit kan også føre til alt for generaliseret design, hvilket gør det sværere at begrænse de slags komponenter, der kan føjes til en container. Da du ikke er i stand til at stole på, at kompilatoren håndhæver typebegrænsninger, bliver du nødt til at bruge runtime-kontrol.

Hvad er der galt med runtime-typecheck?

Kørselstypekontrol involverer hvis udsagn og forekomst af operatør, hvilket fører til skør kode. Hvis du glemmer at opdatere en runtime-typecheck, når dine applikationskrav udvikler sig, kan du efterfølgende introducere bugs.

Det er også muligt at vælge et passende designmønster og bruge det forkert. Det Dobbelt-kontrolleret låsning mønster er et klassisk eksempel. Dobbeltkontrolleret låsning reducerer låsefikseringsomkostningerne ved først at teste et låsekriterium uden faktisk at erhverve låsen og derefter kun erhverve låsen, hvis kontrollen indikerer, at låsning er påkrævet. Mens det så godt ud på papir, havde dobbeltkontrolleret låsning i JDK 1.4 nogle skjulte kompleksiteter. Da JDK 5 udvidede semantikken i flygtige nøgleord var udviklere endelig i stand til at høste fordelene ved det dobbeltkontrollerede låsemønster.

Mere om dobbeltkontrolleret låsning

Se "Dobbeltkontrolleret låsning: Smart, men brudt" og "Kan dobbeltkontroleret låsning løses?" (Brian Goetz, JavaWorld) for at lære mere om, hvorfor dette mønster ikke fungerede i JDK 1.4 og tidligere. For mere om specificering af DCL i JDK 5 og senere, se "The 'Double-Checked Locking is Broken' Declaration" (University of Maryland Department of Computer Science, David Bacon, et al.).

Anti-mønstre

Når et designmønster ofte bruges, men er ineffektivt og / eller kontraproduktivt, er designmønstret kendt som et anti-mønster. Man kan argumentere for, at dobbeltkontrolleret låsning som brugt i JDK 1.4 og tidligere var et antimønster. Jeg vil sige, at det kun var en dårlig idé i den sammenhæng. For at en dårlig idé kan udvikle sig til et antimønster, skal følgende betingelser være opfyldt (se Ressourcer).

  • Et gentaget handlingsmønster, proces eller struktur, der oprindeligt ser ud til at være gavnligt, men i sidste ende giver flere dårlige konsekvenser end gavnlige resultater.
  • Der findes en alternativ løsning, der er tydeligt dokumenteret, dokumenteret i praksis og gentagelig.

Mens dobbeltkontrolleret låsning i JDK 1.4 opfyldte det første krav om et antimønster, opfyldte det ikke det andet: selvom du kunne bruge synkroniseret for at løse problemet med doven initialisering i et multitrådet miljø, ville det have besejret grunden til at bruge dobbeltkontrolleret låsning i første omgang.

Deadlock anti-mønstre

At anerkende antimønstre er en forudsætning for at undgå dem. Læs Obi Ezechukwus tredelte serie for en introduktion til tre antimønstre, der er berømte for at forårsage dødvande:

  • Ingen voldgift
  • Samling af arbejdere
  • Inkrementel låsning

Design mønster historie

Designmønstre dateres tilbage til slutningen af ​​1970'erne med offentliggørelsen af Et mønster sprog: Byer, bygninger, byggeri af arkitekt Christopher Alexander og et par andre. Denne bog introducerede designmønstre i en arkitektonisk sammenhæng og præsenterede 253 mønstre, der samlet dannede, hvad forfatterne kaldte en mønster sprog.

Ironien i designmønstre

Selvom designmønstre, der bruges til softwaredesign, sporer deres begyndelse til Et mønster sprog, dette arkitektoniske arbejde blev påvirket af det daværende sprog til beskrivelse af computerprogrammering og design.

Konceptet med et mønstersprog opstod efterfølgende i Donald Normans og Stephen Drapers Brugercentreret systemdesign, som blev udgivet i 1986. Denne bog foreslog anvendelse af mønster-sprog til interaktionsdesign, som er praksis med at designe interaktive digitale produkter, miljøer, systemer og tjenester til menneskelig brug.

I mellemtiden var Kent Beck og Ward Cunningham begyndt at undersøge mønstre og deres anvendelighed til software design. I 1987 brugte de en række designmønstre til at hjælpe Tektronixs Semiconductor Test Systems Group, som havde problemer med at afslutte et designprojekt. Beck og Cunningham fulgte Alexanders råd om brugercentreret design (lade repræsentanter for projektets brugere bestemme designresultatet), samtidig med at de også fik nogle designmønstre for at gøre jobbet lettere.

Erich Gamma indså også vigtigheden af ​​tilbagevendende designmønstre, mens han arbejdede på sin ph.d.-afhandling. Han mente, at designmønstre kunne lette opgaven med at skrive genanvendelig objektorienteret software og overvejede, hvordan man effektivt kunne dokumentere og kommunikere dem. Forud for den europæiske konference om objektorienteret programmering i 1991 begyndte Gamma og Richard Helm at katalogisere mønstre.

På en OOPSLA-workshop, der blev afholdt i 1991, blev Gamma og Helm sammen med Ralph Johnson og John Vlissides. Det her Bande af fire (GoF), som de senere blev kendt, fortsatte med at skrive det populære Designmønstre: Elementer af genanvendelig objektorienteret software, der dokumenterer 23 designmønstre i tre kategorier.

Den moderne udvikling af designmønstre

Designmønstre har fortsat med at udvikle sig siden den originale GoF-bog, især da softwareudviklere har konfronteret nye udfordringer relateret til skiftende hardware- og applikationskrav.

I 1994 blev en amerikansk-baseret nonprofitorganisation kendt som Hillside Group indviet Mønster sprog for programmer, en gruppe af årlige konferencer, hvis mål er at udvikle og forfine kunsten til software design mønstre. Disse igangværende konferencer har givet mange eksempler på domænespecifikke designmønstre. For eksempel designmønstre i en samtidig sammenhæng.

Christopher Alexander hos OOPSLA

OOPSLA 96's hovedtale blev leveret af arkitekten Christopher Alexander. Alexander reflekterede over hans arbejde og om, hvordan det objektorienterede programmeringssamfund havde ramt og savnet marken ved at vedtage og tilpasse sine ideer om mønstersprog til software. Du kan læse Alexanders adresse fuldt ud: "Mønsterteoriens oprindelse: Teoriens fremtid og generation af en levende verden."

I 1998 frigav Mark Grand Mønstre i Java. Denne bog omfattede designmønstre, der ikke findes i GoF-bogen, inklusive samtidige mønstre. Grand brugte også Unified Modeling Language (UML) til at beskrive designmønstre og deres løsninger. Bogens eksempler blev udtrykt og beskrevet på Java-sproget.

Software design mønstre efter klassificering

Moderne softwaredesignmønstre er stort set klassificeret i fire kategorier baseret på deres anvendelse: skabelses-, strukturel, adfærdsmæssig og samtidighed. Jeg vil diskutere hver kategori og derefter opregne og beskrive nogle af de fremtrædende mønstre for hver enkelt.

Andre typer designmønstre

Hvis du tænker, at der er flere typer mønstre, har du ret. En senere artikel i denne serie vil diskutere yderligere designmønstertyper: interaktion, arkitektoniske, organisatoriske og kommunikations- / præsentationsmønstre.

Skabelsesmønstre

EN skabelsesmønster abstraherer processen med instantiering og adskiller, hvordan objekter oprettes, sammensættes og repræsenteres fra den kode, der er afhængig af dem. Klasseskabelsesmønstre Brug arv til at variere de klasser, der instantieres, og objekt skabelsesmønstre delegere instantiering til andre objekter.

  • Abstrakt fabrik: Dette mønster giver en grænseflade til at indkapsle en gruppe individuelle fabrikker, der har et fælles tema uden at specificere deres konkrete klasser.
  • Bygger: Adskiller konstruktionen af ​​et komplekst objekt fra dets repræsentation, hvilket gør det muligt for den samme byggeproces at skabe forskellige repræsentationer. Abstraktion af trinene til objektkonstruktion tillader forskellige implementeringer af trinnene at konstruere forskellige repræsentationer af objekterne.
  • Fabriksmetode: Definerer en grænseflade til oprettelse af et objekt, men lader underklasser bestemme, hvilken klasse der skal instantieres. Dette mønster lader en klasse udsætte instantiering til underklasser. Afhængighedsindsprøjtning er et relateret mønster. (Se ressourcer.)
  • Lazy initialisering: Dette mønster giver os en måde at forsinke oprettelse af objekter, databaseopslag eller en anden dyr proces, indtil resultatet er nødvendigt første gang.
  • Multiton: Udvider på singleton-konceptet til at administrere et kort over navngivne klasseinstanser som nøgleværdipar og giver et globalt adgangspunkt til dem.
  • Objekt pool: Hold et sæt initialiserede objekter klar til brug i stedet for at blive allokeret og destrueret efter behov. Hensigten er at undgå dyr ressourceopsamling og genvinding ved at genbruge objekter, der ikke længere er i brug.
  • Prototype: Angiver de typer objekter, der skal oprettes ved hjælp af en prototypisk forekomst, og opret derefter nye objekter ved at kopiere denne prototype. Den prototypiske forekomst klones for at generere nye objekter.
  • Ressourceopsamling er initialisering: Dette mønster sikrer, at ressourcer automatisk og korrekt initialiseres og genvindes ved at binde dem til egnede objekters levetid. Ressourcer erhverves under initialisering af objektet, når der ikke er nogen chance for, at de bliver brugt, før de er tilgængelige, og frigives med destruktion af de samme objekter, hvilket garanteret finder sted selv i tilfælde af fejl.
  • Singleton: Sikrer, at en klasse kun har én forekomst og giver et globalt adgangspunkt til denne forekomst.