Prototype

Prototype – Definition

Es wird eine prototypische Instanz für ein Objekt erstellt. Neue Objekte werden erstellt, indem dieser Prototyp kopiert wird.

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

Gang of four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)

Prototype – Struktur

Prototyp – Pseudocode

interface Prototype
	// wird benötigt um eine sogenannte "Tiefe Kopie" zu erstellen.
	// dies beinhaltet alle Elemente des aktuellen objekts, sowie allen
	// anderen Referenztypen, die von dem aktuellen Objekt verwendet werden.
	method deepCopy()
	// wird benötigt um eine "Flache Kopie" zu erstellen.
	// Eine flache Kopie beinhaltet ausschließlich die Werte des aktuellen
	// objekts. Sollte ein Referenztyp integriert sein, so wird dieser nicht
	// kopiert, sondern als Referenz verknüpft
	method shallowCopy()
	// Ein Klon ist eine exakte Abbildung des Originals.
	// Dies beinhaltet auch die möglicherweise verwendeten IDs.
	method clone()
	
class ConcretePrototype implements Prototype
	fielt id : int
	// stellvertretend für alle Wertetypen, wie z.B. ein integer
	field value : any
	// stellvertretend für alle Referenztypen, wie z.B. ein string
	// obwohl ein string eigentlich eine kleine besonderheit ist :-)
	field reference : any
	// falls wir ein anderen Prototypen in dem Datenmodel haben
	// können wir uns natürlich die vorhandene Logik zunutze machen
	field other : IPrototype
	
	method deepCopy() : ConcretePrototype
		clone = new ConcretePrototype()
		clone.value = this.value
		// Für den Referenztypen wird immer eine neue Instanz erzeugt
		// d.h. Es gibt immer eine neue Adresse im Speicher
		clone.reference = new string(this.reference)
		// hier wird lediglich der Befehl weitergereicht
		clone.other = other.deepCopy()
	
	method shallowCopy() : ConcretePrototype
		clone = new ConcretePrototype()
		clone.value = this.value
		// Hier werden lediglich die Referenzen kopiert. Beide Objekte sind
		// komplett identisch. Änderungen an der Kopie haben auch Auswirkungen
		// auf das original
		clone.reference = this.reference
		// auch der prototyp wird kopiert
		clone.other = this.other
		
	method clone() : ConcretePrototype
		clone = deepCopy()
		// zusätzlich wird noch die ID kopiert (falls vorhanden)
		clone.id = this.id
		// ein vorhandener Prototyp wird ebenfalls geklont
		clone.other = this.other.clone()
	
program Client
	data = new ConcretePrototype()
	data.id = 42
	data.value = 3.14
	data.reference = "Hello World"
	// ...
	copy1 = data.deepCopy()
	copy2 = data.shallowCopy()
	copy3 = data.clone()
	// ...
	data.reference = "Hallo Welt"
	//
	// WERTE
	// copy1.reference = "Hello World"
	// copy2.reference = "Hallo Welt"
	// copy3.reference = "Hello World"
	// copy1.id = 0
	// copy2.id = 0
	// copy3.id = 42

Prototype – C# Implementierung

Hier am Beispiel einer Bibliothek. Der vollständige Quellcode ist auf github hier zu finden.

public interface IPrototype<out T>
{
	T Clone();
}

public class IdentifierInfo : IPrototype<IdentifierInfo>
{
	public Guid Value { get; private set; }

	public IdentifierInfo Clone()
	{
		var clone = new IdentifierInfo();
		clone.Value = Value;
	}
}

public class Page : IPrototype<Page>
{
	public IdentifierInfo Id { get; private set; } = new IdentifierInfo();
	public string Content { get; set; }

	public Page Clone()
	{
		var clone = new Page();
		clone.Id = Id.Clone();
		clone.Content = string.Copy(Content);
		return clone;
	}
}

public class Person : IPrototype<Person>
{
	public IdentifierInfo Id { get; } = new IdentifierInfo();
	public string Name { get; set; }

	public Person Clone()
		=> throw new CloneNotSupportedException();
}

public class Book : IPrototype<Book>
{
	public IdentifierInfo Id { get; set; } = new IdentifierInfo();
	public string Title { get; }
	public Person Author { get; }
	public IList<Page> Pages { get; set; }

	public Book Clone()
	{
		Book clone = new Book();
		clone.Id = Id.Clone();
		clone.Title = string.Copy(Title);
		clone.Author = Author;
		clone.Pages = Pages.Select(p => p.Clone()).ToList();
		
		return clone;
	}
}