het hoofdstuk gaat door zeven problemen die moeten worden aangepakt om Lexi goed te ontwerpen, inclusief eventuele beperkingen die moeten worden gevolgd. Elk probleem wordt grondig geanalyseerd en er worden oplossingen voorgesteld., Elke oplossing wordt volledig uitgelegd, met inbegrip van pseudo-code en een licht gewijzigde versie van Object Modeling techniek waar van toepassing.
ten slotte wordt elke oplossing direct geassocieerd met een of meer ontwerppatronen. Het wordt getoond hoe de oplossing een directe implementatie van dat ontwerppatroon is.
De zeven problemen (met inbegrip van hun beperkingen) en hun oplossingen (met inbegrip van het patroon(en) waarnaar wordt verwezen), zijn als volgt:
Document StructureEdit
het document is “een arrangement van basis grafische elementen” zoals tekens, lijnen, andere vormen, enz.,, dat “de totale informatie-inhoud van het document vast te leggen”(blz. 35). De structuur van het document bevat een verzameling van deze elementen, en elk element kan op zijn beurt een onderstructuur van andere elementen zijn.
problemen en beperkingen
- tekst en afbeeldingen moeten op dezelfde manier worden behandeld (dat wil zeggen, afbeeldingen zijn geen afgeleid exemplaar van tekst, noch vice versa)
- de implementatie moet complexe en eenvoudige structuren op dezelfde manier behandelen. Het zou niet het verschil tussen de twee moeten weten.,
- specifieke derivaten van abstracte elementen moeten gespecialiseerde analytische elementen hebben.
oplossing en patroon
een recursieve compositie is een hiërarchische structuur van elementen, die “steeds complexer wordende elementen uit eenvoudigere elementen” bouwt (blz.36). Elk knooppunt in de structuur kent zijn eigen kinderen en zijn ouder. Als een operatie op de hele structuur moet worden uitgevoerd, roept elk knooppunt de operatie op zijn kinderen (recursief) aan.
Dit is een implementatie van het samengestelde patroon, dat een verzameling knooppunten is., Het knooppunt is een abstracte basisklasse, en derivaten kunnen bladeren (enkelvoud) zijn, of verzamelingen van andere knooppunten (die op hun beurt bladeren of collectieknooppunten kunnen bevatten). Wanneer een operatie wordt uitgevoerd op de ouder, wordt die operatie recursief doorgegeven aan de hiërarchie.
FormattingEdit
formatteren verschilt van structuur. Formatteren is een methode om een bepaalde instantie van de fysieke structuur van het document te construeren. Dit omvat het breken van tekst in regels, het gebruik van koppeltekens, het aanpassen voor Marge breedtes, enz.,
problemen en beperkingen
- evenwicht tussen (opmaak) kwaliteit, snelheid en opslagruimte
- houd opmaak onafhankelijk (ontkoppeld) van de documentstructuur.
oplossing en patroon
een Compositor-klasse bevat het algoritme dat wordt gebruikt om een compositie te formatteren. Compositor is een subklasse van het primitieve object van de structuur van het document. Een Compositor heeft een bijbehorende instantie van een Compositieobject., Wanneer een Compositor zijn Compose()
uitvoert, herhaalt het elk element van de bijbehorende compositie en herschikt het de structuur door rij-en Kolomobjecten in te voegen indien nodig.
De Compositor zelf is een abstracte klasse, waardoor afgeleide klassen verschillende opmaakalgoritmen kunnen gebruiken (zoals dubbele spatiëring, bredere marges, enz.)
Het Strategiepatroon wordt gebruikt om dit doel te bereiken. Een strategie is een methode van het inkapselen van meerdere algoritmen te gebruiken op basis van een veranderende context., In dit geval moet de opmaak anders zijn, afhankelijk van of tekst, afbeeldingen, eenvoudige elementen, enz., worden geformatteerd.
verfraaien van de Gebruikersinterfaceedit
de mogelijkheid om de grafische interface te wijzigen die de gebruiker gebruikt om met het document te communiceren.,
Problemen en Beperkingen
- het Afbakenen van een pagina tekst met een kader rond het te bewerken gebied
- schuifbalken waarmee de gebruiker verschillende delen van de pagina
- gebruikersinterface-objecten niet mag weten over de versieringen
- Vermijd een “explosie van classes”, die zou worden veroorzaakt door subclassificering voor “elke mogelijke combinatie van versieringen” en elementen (blz. 44)
de Oplossing en het Patroon
Het gebruik van een transparante behuizing kan elementen die uitbreiding van het gedrag van de samenstelling worden toegevoegd aan een compositie., Deze elementen, zoals rand en Scroller, zijn speciale subklassen van het enkelvoud element zelf. Dit maakt het mogelijk de compositie te vergroten, effectief toe te voegen state-achtige elementen. Omdat deze uitbreidingen deel uitmaken van de structuur, zal hun juiste Operation()
aangeroepen worden als Operation()
aangeroepen wordt. Dit betekent dat de klant geen speciale kennis of interface met de structuur nodig heeft om de versieringen te kunnen gebruiken.,
Dit is een Decoratiepatroon, een patroon dat verantwoordelijkheden toevoegt aan een object zonder het object zelf te wijzigen.
Ondersteunt meerdere Look-And-Feel Standaardsedit
Look-and-feel verwijst naar platformspecifieke UI-standaarden. Deze normen “definiëren richtlijnen voor hoe applicaties verschijnen en reageren op de gebruiker” (blz. 47).
problemen en beperkingen
- De editor moet standaarden van meerdere platforms implementeren zodat deze draagbaar is
- gemakkelijk aan te passen aan nieuwe en opkomende standaarden
- laat runtime veranderen van look-and-feel (d.w.z.,: Geen hard-codering)
- hebben een set van abstracte elementaire subklassen voor elke categorie van elementen (schuifbalk, knoppen, enz.)
- hebben een set van concrete subklassen voor elke abstracte subklasse die een andere look-and-feel standaard kan hebben. (Schuifbalk met MotifScrollBar en PresentationScrollBar voor Look-and-feel van motief en presentatie)
oplossing en patroon
aangezien het maken van verschillende concrete objecten niet kan worden gedaan tijdens runtime, moet het proces voor het maken van objecten worden geabstraheerd., Dit wordt gedaan met een abstracte guiFactory, die de verantwoordelijkheid op zich neemt voor het creëren van UI-elementen. De abstracte guiFactory heeft concrete implementaties, zoals MotifFactory, die concrete elementen van het juiste type creëert (MotifScrollBar). Op deze manier hoeft het programma alleen maar om een schuifbalk te vragen en krijgt het tijdens de uitvoering het juiste concrete element.
Dit is een abstracte fabriek. Een gewone fabriek creëert betonnen objecten van één type. Een abstracte fabriek creëert concrete objecten van verschillende types, afhankelijk van de concrete uitvoering van de fabriek zelf., Zijn vermogen om zich te concentreren op niet alleen concrete objecten, maar hele families van concrete objecten “onderscheidt het van andere creatieve patronen, die slechts één soort product object betrekken” (PP. 51).
Ondersteunt meerdere Venstersystemenbedit
net zoals look-and-feel verschillend is tussen platforms, zo is de methode voor het omgaan met windows. Elk platform displays, lay-out, behandelt input naar en output van, en lagen vensters anders.,
problemen en beperkingen
- De documentbewerker moet draaien op veel van de “belangrijke en grotendeels incompatibele venstersystemen” die bestaan (p. 52)
- Een abstracte fabriek kan niet worden gebruikt. Vanwege verschillende standaarden zal er geen gemeenschappelijke abstracte klasse zijn voor elk type widget.
- maak geen nieuw, Niet-standaard venstersysteem
oplossing en patroon
Het is mogelijk om “onze eigen abstracte en concrete productklassen” te ontwikkelen, omdat “alle venstersystemen over het algemeen hetzelfde doen” (p. 52)., Elk window systeem biedt bewerkingen voor het tekenen van primitieve vormen, iconifying / de-iconifying, resizing, en verfrissende window inhoud.
een abstracte basis Window
klasse kan worden afgeleid van de verschillende types van bestaande vensters, zoals toepassing, iconified, dialoogvenster. Deze klassen zullen bewerkingen bevatten die geassocieerd zijn met windows, zoals het opnieuw vormgeven, grafisch verversen, enz. Elk venster bevat elementen waarvan Draw()
functies worden aangeroepen door de Window
’s eigen draw-gerelateerde functies.,
om te voorkomen dat platformspecifieke Venstersubklassen voor elk mogelijk platform moeten worden aangemaakt, zal een interface worden gebruikt. DeWindow
klasse zal een Window
implementatie (WindowImp
) abstracte klasse implementeren. Deze klasse zal dan op zijn beurt worden afgeleid in meerdere platform-specifieke implementaties, elk met platform – specifieke operaties., Daarom zijn slechts één set van Window
klassen nodig voor elk type van Window
, en slechts één set van WindowImp
klassen nodig voor elk platform (in plaats van het Cartesiaanse product van alle beschikbare types en platforms). Bovendien vereist het toevoegen van een nieuw venstertype geen wijziging van de platformimplementatie, of vice versa.
Dit is een Brugpatroon. Window
en WindowImp
zijn verschillend, maar gerelateerd., Window
behandelt vensters in het programma, en WindowImp
behandelt vensters op een platform. Een van hen kan veranderen zonder ooit de andere te hoeven wijzigen. Het Brugpatroon maakt het mogelijk dat deze twee “afzonderlijke klassenhiërarchieën samenwerken, zelfs als ze onafhankelijk evolueren” (p. 54).
Gebruikersbewerk
alle acties die de gebruiker met het document kan ondernemen, variërend van het invoeren van tekst, het veranderen van opmaak, stoppen, opslaan, enz.,
problemen en beperkingen
- operaties moeten benaderd worden via verschillende ingangen, zoals een menuoptie en een sneltoets voor hetzelfde commando
- elke optie heeft een interface, die aanpasbaar moet zijn
- operaties zijn geïmplementeerd in verschillende klassen
- om koppeling te voorkomen, mogen er niet veel afhankelijkheden zijn tussen implementatie-en gebruikersinterfaceklassen.,
- Undo en redo commando ‘ s moeten worden ondersteund op de meeste document veranderende bewerkingen, zonder willekeurige limiet op het aantal niveaus van undo
- functies zijn niet levensvatbaar, omdat ze niet gemakkelijk ongedaan maken/redo, zijn niet gemakkelijk geassocieerd met een toestand, en zijn moeilijk uit te breiden of te hergebruiken.
- menu ‘ s moeten worden behandeld als hiërarchische samengestelde structuren. Vandaar, een menu is een menu-item dat menu-items bevat die andere menu-items kunnen bevatten, enz.,
oplossing en patroon
elk menu-item, in plaats van te worden geïnstantieerd met een lijst met parameters, wordt in plaats daarvan gedaan met een commando-object.
Commando is een abstract object dat slechts een enkele abstracte Execute()
methode heeft. Afgeleide objecten breiden de methode Execute()
correct uit (d.w.z. de PasteCommand.Execute()
zou de klembordbuffer van de Inhoud gebruiken). Deze objecten kunnen worden gebruikt door widgets of knoppen net zo gemakkelijk als ze kunnen worden gebruikt door menu-items.,
om ongedaan maken en opnieuw uitvoeren te ondersteunen, wordt Command
ook gegeven Unexecute()
en Reversible()
. In afgeleide klassen bevat de eerste code die dat commando Ongedaan zal maken, en de laatste geeft een Booleaanse waarde terug die bepaalt of het commando niet uitvoerbaar is. Reversible()
staat toe dat sommige commando ‘ s niet-ongedaan gemaakt kunnen worden, zoals een Save Commando.
alle uitgevoerde Commands
worden bewaard in een lijst met een methode om een” present ” marker direct na het meest recent uitgevoerde commando te behouden., Een verzoek om ongedaan te maken zal Command.Unexecute()
direct voor “present” aanroepen, en vervolgens “present” één commando terugzetten. Omgekeerd zal een Redo
verzoek Command.Execute()
na “present” aanroepen en “present” doorsturen.
deze Command
benadering is een implementatie van het Opdrachtpatroon. Het kapselt verzoeken in objecten, en maakt gebruik van een gemeenschappelijke interface om toegang te krijgen tot deze verzoeken. Dus, de client kan omgaan met verschillende verzoeken, en opdrachten kunnen worden verspreid over de toepassing.,
spellingcontrole en Afbreekbewerking
Dit is de mogelijkheid van de documentbewerker om tekstueel de inhoud van een document te analyseren. Hoewel er veel analyses kunnen worden uitgevoerd, staan spellingcontrole en afbreekopmaak centraal.
problemen en beperkingen
- staan meerdere manieren toe om de spelling te controleren en plaatsen te identificeren voor afbreek
- laat uitbreiding toe voor toekomstige analyse (bijv. woordaantal, grammaticacontrole)
- in staat zijn om door de inhoud van een tekst te itereren zonder toegang tot de werkelijke structuur van de tekst (bijv.,, array, linked list, string)
- laat elke manier van document doorlopen (van begin tot eind, van eind tot begin, alfabetische volgorde, enz.)
oplossing en patroon
het verwijderen van de integer-gebaseerde index uit het basiselement maakt het mogelijk een andere iteratie-interface te implementeren. Dit vereist extra methoden voor traversal en object retrieval. Deze methoden worden in een abstracte Iterator
interface geplaatst., Elk element implementeert dan een afleiding van de Iterator
, afhankelijk van hoe dat element zijn lijst behoudt (ArrayIterator
, LinkListIterator
, enz.).
functies voor traversal en retrieval worden in de abstracte Iterator interface geplaatst. Toekomstige Iterators kunnen worden afgeleid op basis van het type lijst waar ze doorheen zullen itereren, zoals Arrays of gekoppelde lijsten. Dus, het maakt niet uit wat voor soort indexeringsmethode een implementatie van het element gebruikt, het zal de juiste Iterator hebben.
Dit is een implementatie van het Iteratorpatroon., Het stelt de client in staat om door elke objectcollectie te bladeren, zonder rechtstreeks toegang te hebben tot de inhoud van de collectie, of zich zorgen te maken over het type lijst dat de structuur van de collectie gebruikt.
nu traversal is afgehandeld, is het mogelijk om de elementen van een structuur te analyseren. Het is niet haalbaar om elk type analyse in de elementstructuur zelf op te bouwen; elk element zou gecodeerd moeten worden, en veel van de code zou hetzelfde zijn voor soortgelijke elementen.
in plaats daarvan wordt een generiekeCheckMe()
methode ingebouwd in de abstracte klasse van het element., Elke Iterator krijgt een verwijzing naar een specifiek algoritme (zoals spellingcontrole, grammaticacontrole, enz.). Wanneer die Iterator door zijn verzameling itereert, roept het elk element CheckMe
aan, waarbij het gespecificeerde algoritme wordt doorgegeven. CheckMe
geeft dan een verwijzing naar het element terug naar dat algoritme voor analyse.
om een spellingcontrole uit te voeren, zou een front-to-end iterator een verwijzing krijgen naar een SpellCheck
object., De iterator zou dan toegang krijgen tot elk element en zijn CheckMe()
methode uitvoeren met de SpellCheck
parameter. Elke CheckMe
zou dan de SpellCheck
aanroepen, waarbij een verwijzing naar het juiste element wordt doorgegeven.
op deze manier kan elk algoritme worden gebruikt met elke traversale methode, zonder hard-code koppeling met elkaar. Bijvoorbeeld, Find kan worden gebruikt als “find next” Of “find previous”, afhankelijk van of een” forward “iterator werd gebruikt, of een” backwards ” iterator.,
bovendien kunnen de algoritmen zelf verantwoordelijk zijn voor het omgaan met verschillende elementen. Bijvoorbeeld, eenSpellCheck
algoritme zou eenGraphic
element negeren, in plaats van elkGraphic
-afgeleid element te programmeren om zichzelf niet naar eenSpellCheck
te sturen.