Prototypemønster - Prototype pattern

Den prototype mønster er en skabende design mønster i softwareudvikling . Det bruges, når typen af objekter, der skal oprettes, bestemmes af en prototypisk forekomst , som klones for at producere nye objekter. Dette mønster bruges til at undgå underklasser af en objektopretter i klientprogrammet, ligesom fabriksmetodemønsteret gør og for at undgå de iboende omkostninger ved at oprette et nyt objekt på standardmåden (f.eks. Ved hjælp af det ' nye ' søgeord), når det er uoverkommeligt dyrt for en given applikation.

For at implementere mønsteret, erklær en abstrakt basisklasse, der angiver en ren virtuel klon () metode. Enhver klasse, der har brug for en " polymorf konstruktør " -kapacitet, stammer fra den abstrakte basisklasse og implementerer klon () -operationen.

Klienten, i stedet for at skrive kode, der påkalder den "nye" operator på et hårdt kodet klassenavn, kalder klon () -metoden på prototypen, kalder en fabriksmetode med en parameter, der angiver den ønskede konkrete afledte klasse , eller påberåber klon () metode gennem en eller anden mekanisme leveret af et andet designmønster.

Den mitotiske deling af en celle - hvilket resulterer i to identiske celler - er et eksempel på en prototype, der spiller en aktiv rolle i at kopiere sig selv og dermed demonstrerer prototypemønsteret. Når en celle deler sig, resulterer to celler af identisk genotype. Med andre ord kloner cellen sig selv.

Oversigt

Prototypedesignmønsteret er et af de tre velkendte GoF-designmønstre, der beskriver, hvordan man løser tilbagevendende designproblemer til at designe fleksibel og genanvendelig objektorienteret software, det vil sige objekter, der er lettere at implementere, ændre, teste og genbruge.

Prototypedesignmønsteret løser problemer som:

  • Hvordan kan objekter oprettes, så hvilke objekter der skal oprettes, kan specificeres i løbetid?
  • Hvordan kan dynamisk belastede klasser instantieres?

Oprettelse af objekter direkte i klassen, der kræver (bruger) objekterne, er ufleksibel, fordi den forpligter klassen til bestemte objekter på kompileringstidspunktet og gør det umuligt at angive, hvilke objekter der skal oprettes i løbetid.

Prototypedesignmønsteret beskriver, hvordan man løser sådanne problemer:

  • Definer et Prototypeobjekt, der returnerer en kopi af sig selv.
  • Opret nye objekter ved at kopiere et Prototypeobjekt.

Dette muliggør konfiguration af en klasse med forskellige Prototypeobjekter, som kopieres for at oprette nye objekter, og endnu mere kan Prototypeobjekter tilføjes og fjernes ved løbetid.
Se også UML -klassen og sekvensdiagrammet herunder.

Struktur

UML klasse og sekvensdiagram

Image
Et eksempel på et UML -klasse- og sekvensdiagram for prototypedesignmønsteret.

I den ovennævnte UML klasse diagram , den Clientklasse refererer til Prototypeinterface til kloning af et Product. Den Product1klasse implementerer Prototypeinterfacet ved at oprette en kopi af sig selv.
De UML sekvensdiagram viser de runtime-interaktioner: Clientobjekt opkald clone()på et prototype:Product1objekt, som skaber og returnerer en kopi af sig selv (en product:Product1genstand).

UML klassediagram

Image
UML klassediagram, der beskriver prototypedesignmønsteret

Tommelfingerregler

Nogle gange overlapper kreationsmønstre - der er tilfælde, hvor enten prototype eller abstrakt fabrik ville være passende. På andre tidspunkter supplerer de hinanden: abstrakt fabrik lagrer muligvis et sæt prototyper, hvorfra man kan klone og returnere produktobjekter ( GoF , s126). Abstrakt fabrik, bygherre og prototype kan bruge singleton i deres implementeringer. (GoF, s81, 134). Abstrakte fabrikklasser implementeres ofte med fabriksmetoder (oprettelse gennem arv ), men de kan implementeres ved hjælp af prototype (oprettelse gennem delegering ). (GoF, s95)

Ofte starter designs med fabriksmetoden (mindre kompliceret, mere tilpasselig, underklasser formerer sig) og udvikler sig mod abstrakt fabrik, prototype eller bygherre (mere fleksibel, mere kompleks), da designeren opdager, hvor der er behov for mere fleksibilitet. (GoF, s136)

Prototype kræver ikke underklassificering, men det kræver en "initialiserings" -operation. Fabriksmetode kræver underklassificering, men kræver ikke initialisering. (GoF, s116)

Design, der gør stor brug af komposit- og dekoratormønstre , kan ofte også have gavn af Prototype. (GoF, s126)

Tommelfingerreglen kan være, at du bliver nødt til at klone () et objekt, når du vil oprette et andet objekt ved runtime, der er en ægte kopi af det objekt, du kloner. Ægte kopi betyder, at alle attributterne for det nyoprettede objekt skal være de samme som det objekt, du kloner. Hvis du kunne have instantieret klassen ved at bruge nyt i stedet, ville du få et objekt med alle attributter som deres oprindelige værdier. For eksempel, hvis du designer et system til udførelse af bankkontotransaktioner, vil du gerne lave en kopi af det objekt, der indeholder dine kontooplysninger, udføre transaktioner på det og derefter erstatte det originale objekt med det ændrede. I sådanne tilfælde vil du gerne bruge klon () i stedet for ny.

Kodeprøver

Pseudokode

Lad os skrive en forekomstbrowser klasse for en tekst. Denne klasse viser forekomsten af ​​et ord i en tekst. Et sådant objekt er dyrt at oprette, da placeringen af ​​forekomsterne har brug for en dyr proces at finde. Så for at kopiere et sådant objekt bruger vi prototypemønsteret:

class WordOccurrences is
    field occurrences is
        The list of the index of each occurrence of the word in the text.

    constructor WordOccurrences(text, word) is
            input: the text in which the occurrences have to be found
            input: the word that should appear in the text
        Empty the occurrences list
        for each textIndex in text
            isMatchingg:= true
            for each wordIndex in word
                if the current word character does not match the current text character then
                    isMatchingg:= false
            if isMatching is true then
                Add the current textIndex into the occurrences list

    method getOneOccurrenceIndex(n) is
            input: a number to point on the nth occurrence.
            output: the index of the nth occurrence.
        Return the nth item of the occurrences field if any.

    method clone() is
            output: a WordOccurrences object containing the same data.
        Call clone() on the super class.
        On the returned object, set the occurrences field with the value of the local occurrences field.
        Return the cloned object.

texte:= "The prototype pattern is a creational design pattern in software development first described in design patterns, the book."
wordw:= "pattern"d
searchEnginen:= new WordOccurrences(text, word)
anotherSearchEngineE:= searchEngine.clone()

(søge -algoritmen er ikke optimeret; det er en grundlæggende algoritme til at illustrere mønsterimplementeringen)

C# eksempel

Den konkrete objekttype er skabt ud fra dens prototype. MemberwiseClone bruges i Clone -metoden til at oprette og returnere en kopi af ConcreteFoo1 eller ConcreteFoo2.

public abstract class Foo
{
    // normal implementation

    public abstract Foo Clone();
}

public class ConcreteFoo1 : Foo
{
    public override Foo Clone()
    {
        return (Foo)this.MemberwiseClone(); // Clones the concrete class.
    }
}

public class ConcreteFoo2 : Foo
{
    public override Foo Clone()
    {
        return (Foo)this.MemberwiseClone(); // Clones the concrete class.
    }
}

C ++ eksempel

Diskussion af designmønsteret sammen med en komplet illustrativ eksempelimplementering ved hjælp af polymorf klassedesign findes i C ++ - annotationerne .

Java eksempel

Dette mønster skaber den slags objekt ved hjælp af dets prototype. Med andre ord, mens klassen opretter objektet til Prototype -objekt, opretter klassen en klon af det og returnerer det som prototype. Klonmetoden er blevet brugt til at klone prototypen, når det kræves.

// Prototype pattern
public abstract class Prototype implements Cloneable {
    public Prototype clone() throws CloneNotSupportedException{
        return (Prototype) super.clone();
    }
}
	
public class ConcretePrototype1 extends Prototype {
    @Override
    public Prototype clone() throws CloneNotSupportedException {
        return (ConcretePrototype1)super.clone();
    }
}

public class ConcretePrototype2 extends Prototype {
    @Override
    public Prototype clone() throws CloneNotSupportedException {
        return (ConcretePrototype2)super.clone();
    }
}

PHP eksempel

// The Prototype pattern in PHP is done with the use of built-in PHP function __clone()

abstract class Prototype
{
    public string $a;
    public string $b;
    
    public function displayCONS(): void
    {
        echo "CONS: {$this->a}\n";
        echo "CONS: {$this->b}\n";
    }
    
    public function displayCLON(): void
    {
        echo "CLON: {$this->a}\n";
        echo "CLON: {$this->b}\n";
    }

    abstract function __clone();
}

class ConcretePrototype1 extends Prototype
{
    public function __construct()
    {
        $this->a = "A1";
        $this->b = "B1";
        
        $this->displayCONS();
    }

    function __clone()
    {
        $this->displayCLON();
    }
}

class ConcretePrototype2 extends Prototype
{
    public function __construct()
    {
        $this->a = "A2";
        $this->b = "B2";
        
        $this->displayCONS();
    }

    function __clone()
    {
        $this->a = $this->a ."-C";
        $this->b = $this->b ."-C";
        
        $this->displayCLON();
    }
}

$cP1 = new ConcretePrototype1();
$cP2 = new ConcretePrototype2();
$cP2C = clone $cP2;

// RESULT: #quanton81

// CONS: A1
// CONS: B1
// CONS: A2
// CONS: B2
// CLON: A2-C
// CLON: B2-C

Python eksempel

Python version 3.9+

import copy

class Prototype:
    def clone(self):
        return copy.deepcopy(self)

if __name__ == "__main__":
    prototype = Prototype()
    prototype_copy = prototype.clone()
    print(prototype_copy)

Produktion:

<__main__.Prototype object at 0x7fae8f4e2940>

Se også

Referencer

Kilder