C# Language
Kreationelle Designmuster
Suche…
Bemerkungen
Die Schöpfungsmuster zielen darauf ab, ein System von der Erstellung, Zusammenstellung und Darstellung seiner Objekte zu trennen. Sie erhöhen die Flexibilität des Systems hinsichtlich des Was, Wer, Wie und Wann der Objekterstellung. Kreationsmuster kapseln das Wissen darüber, welche Klassen ein System verwendet, verdecken jedoch die Details, wie die Instanzen dieser Klassen erstellt und zusammengefügt werden. Programmierer haben erkannt, dass das Erstellen von Systemen mit Vererbung diese Systeme zu starr macht. Die kreativen Muster sollen diese enge Kopplung aufheben.
Singleton-Muster
Das Singleton-Muster dient dazu, die Erstellung einer Klasse auf genau eine einzige Instanz zu beschränken.
Dieses Muster wird in einem Szenario verwendet, in dem es sinnvoll ist, nur eines davon zu haben, z.
- eine einzige Klasse, die die Interaktionen anderer Objekte orchestriert, z. Manager-Klasse
- oder eine Klasse, die eine eindeutige, einzige Ressource darstellt, z. Protokollierungskomponente
Eine der häufigsten Methoden zum Implementieren des Singleton-Musters ist eine statische Factory-Methode wie CreateInstance()
oder GetInstance()
(oder eine statische Eigenschaft in C #, Instance
), die darauf ausgelegt ist, immer dieselbe Instanz zurückzugeben.
Beim ersten Aufruf der Methode oder Eigenschaft wird die Singleton-Instanz erstellt und zurückgegeben. Danach gibt die Methode immer dieselbe Instanz zurück. Auf diese Weise gibt es immer nur eine Instanz des Singleton-Objekts.
Das Erstellen von Instanzen über new
kann verhindert werden, indem die Klassenkonstruktoren als private.
Hier ein typisches Codebeispiel zum Implementieren eines Singleton-Musters in C #:
class Singleton
{
// Because the _instance member is made private, the only way to get the single
// instance is via the static Instance property below. This can also be similarly
// achieved with a GetInstance() method instead of the property.
private static Singleton _instance = null;
// Making the constructor private prevents other instances from being
// created via something like Singleton s = new Singleton(), protecting
// against unintentional misuse.
private Singleton()
{
}
public static Singleton Instance
{
get
{
// The first call will create the one and only instance.
if (_instance == null)
{
_instance = new Singleton();
}
// Every call afterwards will return the single instance created above.
return _instance;
}
}
}
Um dieses Muster weiter zu veranschaulichen, prüft der folgende Code, ob eine identische Instanz des Singleton zurückgegeben wird, wenn die Instance-Eigenschaft mehrmals aufgerufen wird.
class Program
{
static void Main(string[] args)
{
Singleton s1 = Singleton.Instance;
Singleton s2 = Singleton.Instance;
// Both Singleton objects above should now reference the same Singleton instance.
if (Object.ReferenceEquals(s1, s2))
{
Console.WriteLine("Singleton is working");
}
else
{
// Otherwise, the Singleton Instance property is returning something
// other than the unique, single instance when called.
Console.WriteLine("Singleton is broken");
}
}
}
Hinweis: Diese Implementierung ist nicht threadsicher.
Weitere Beispiele, wie dieser Thread sicher gemacht werden kann, finden Sie unter Singleton-Implementierung
Singletons sind konzeptionell einem globalen Wert ähnlich und verursachen ähnliche Designfehler und Probleme. Aus diesem Grund wird das Singleton-Muster allgemein als ein Anti-Muster angesehen.
Besuchen Sie "Was ist so schlimm an Singletons?" Weitere Informationen zu den Problemen, die bei ihrer Verwendung auftreten.
In C # haben Sie die Möglichkeit, eine Klasse static
zu machen, wodurch alle Mitglieder statisch werden und die Klasse nicht instanziiert werden kann. Aus diesem Grund ist es üblich, statische Klassen anstelle des Singleton-Musters zu sehen.
Die wichtigsten Unterschiede zwischen den beiden finden Sie unter C # Singleton Pattern versus Static Class .
Fabrikmethode Muster
Factory Method ist eines der kreativen Designmuster. Es wird verwendet, um das Problem der Erstellung von Objekten zu lösen, ohne den genauen Ergebnistyp anzugeben. In diesem Dokument erfahren Sie, wie Sie Factory Method DP richtig verwenden.
Lassen Sie mich Ihnen die Idee an einem einfachen Beispiel erklären. Stellen Sie sich vor, Sie arbeiten in einer Fabrik, in der drei Arten von Geräten hergestellt werden: Amperemeter, Voltmeter und Widerstandsmesser. Sie schreiben ein Programm für einen zentralen Computer, das ein ausgewähltes Gerät erstellt, aber Sie wissen nicht die endgültige Entscheidung Ihres Chefs darüber, was er produzieren soll.
Erstellen wir ein Schnittstellen- IDevice
mit einigen allgemeinen Funktionen, die alle Geräte haben:
public interface IDevice
{
int Measure();
void TurnOff();
void TurnOn();
}
Jetzt können wir Klassen erstellen, die unsere Geräte darstellen. Diese Klassen müssen die IDevice
Schnittstelle implementieren:
public class AmMeter : IDevice
{
private Random r = null;
public AmMeter()
{
r = new Random();
}
public int Measure() { return r.Next(-25, 60); }
public void TurnOff() { Console.WriteLine("AmMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("AmMeter turns on..."); }
}
public class OhmMeter : IDevice
{
private Random r = null;
public OhmMeter()
{
r = new Random();
}
public int Measure() { return r.Next(0, 1000000); }
public void TurnOff() { Console.WriteLine("OhmMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("OhmMeter turns on..."); }
}
public class VoltMeter : IDevice
{
private Random r = null;
public VoltMeter()
{
r = new Random();
}
public int Measure() { return r.Next(-230, 230); }
public void TurnOff() { Console.WriteLine("VoltMeter flashes lights saying good bye!"); }
public void TurnOn() { Console.WriteLine("VoltMeter turns on..."); }
}
Jetzt müssen wir die Factory-Methode definieren. Erstellen wir die DeviceFactory
Klasse mit einer statischen Methode:
public enum Device
{
AM,
VOLT,
OHM
}
public class DeviceFactory
{
public static IDevice CreateDevice(Device d)
{
switch(d)
{
case Device.AM: return new AmMeter();
case Device.VOLT: return new VoltMeter();
case Device.OHM: return new OhmMeter();
default: return new AmMeter();
}
}
}
Großartig! Lassen Sie uns unseren Code testen:
public class Program
{
static void Main(string[] args)
{
IDevice device = DeviceFactory.CreateDevice(Device.AM);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
device = DeviceFactory.CreateDevice(Device.VOLT);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
device = DeviceFactory.CreateDevice(Device.OHM);
device.TurnOn();
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
Console.WriteLine(device.Measure());
device.TurnOff();
Console.WriteLine();
}
}
Dies ist die Beispielausgabe, die nach dem Ausführen dieses Codes angezeigt wird:
AmMeter schaltet sich ein ...
36
6
33
43
24
AmMeter blinkt Lichter und verabschiedet sich!
VoltMeter schaltet sich ein ...
102
-61
85
138
36
VoltMeter blinkt Lichter zum Abschied!
OhmMeter schaltet sich ein ...
723828
368536
685412
800266
578595
OhmMeter blinkt Lichter zum Abschied!
Generator-Muster
Trennen Sie die Konstruktion eines komplexen Objekts von seiner Repräsentation, sodass derselbe Konstruktionsprozess unterschiedliche Repräsentationen erstellen kann und ein hohes Maß an Kontrolle über den Zusammenbau der Objekte bietet.
In diesem Beispiel wird das Builder-Muster veranschaulicht, in dem verschiedene Fahrzeuge Schritt für Schritt zusammengebaut werden. Der Shop verwendet VehicleBuilders, um verschiedene Fahrzeuge in einer Reihe von aufeinanderfolgenden Schritten zu konstruieren.
using System;
using System.Collections.Generic;
namespace GangOfFour.Builder
{
/// <summary>
/// MainApp startup class for Real-World
/// Builder Design Pattern.
/// </summary>
public class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
VehicleBuilder builder;
// Create shop with vehicle builders
Shop shop = new Shop();
// Construct and display vehicles
builder = new ScooterBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new CarBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new MotorCycleBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Director' class
/// </summary>
class Shop
{
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
vehicleBuilder.BuildDoors();
}
}
/// <summary>
/// The 'Builder' abstract class
/// </summary>
abstract class VehicleBuilder
{
protected Vehicle vehicle;
// Gets vehicle instance
public Vehicle Vehicle
{
get { return vehicle; }
}
// Abstract build methods
public abstract void BuildFrame();
public abstract void BuildEngine();
public abstract void BuildWheels();
public abstract void BuildDoors();
}
/// <summary>
/// The 'ConcreteBuilder1' class
/// </summary>
class MotorCycleBuilder : VehicleBuilder
{
public MotorCycleBuilder()
{
vehicle = new Vehicle("MotorCycle");
}
public override void BuildFrame()
{
vehicle["frame"] = "MotorCycle Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
/// <summary>
/// The 'ConcreteBuilder2' class
/// </summary>
class CarBuilder : VehicleBuilder
{
public CarBuilder()
{
vehicle = new Vehicle("Car");
}
public override void BuildFrame()
{
vehicle["frame"] = "Car Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "2500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "4";
}
public override void BuildDoors()
{
vehicle["doors"] = "4";
}
}
/// <summary>
/// The 'ConcreteBuilder3' class
/// </summary>
class ScooterBuilder : VehicleBuilder
{
public ScooterBuilder()
{
vehicle = new Vehicle("Scooter");
}
public override void BuildFrame()
{
vehicle["frame"] = "Scooter Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "50 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
/// <summary>
/// The 'Product' class
/// </summary>
class Vehicle
{
private string _vehicleType;
private Dictionary<string,string> _parts =
new Dictionary<string,string>();
// Constructor
public Vehicle(string vehicleType)
{
this._vehicleType = vehicleType;
}
// Indexer
public string this[string key]
{
get { return _parts[key]; }
set { _parts[key] = value; }
}
public void Show()
{
Console.WriteLine("\n---------------------------");
Console.WriteLine("Vehicle Type: {0}", _vehicleType);
Console.WriteLine(" Frame : {0}", _parts["frame"]);
Console.WriteLine(" Engine : {0}", _parts["engine"]);
Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
Console.WriteLine(" #Doors : {0}", _parts["doors"]);
}
}
}
Ausgabe
Fahrzeugtyp: Scooter Frame: Scooter Frame
Motor: keiner
#Räder: 2
#Türen: 0Fahrzeugtyp: Auto
Rahmen: Auto Frame
Motor: 2500 ccm
#Räder: 4
#Türen: 4Fahrzeugtyp: Motorrad
Frame: MotorCycle Frame
Motor: 500 ccm
#Räder: 2
#Türen: 0
Prototypmuster
Geben Sie die Art der Objekte an, die mithilfe einer prototypischen Instanz erstellt werden sollen, und erstellen Sie neue Objekte, indem Sie diesen Prototyp kopieren.
In diesem Beispiel wird das Prototypmuster veranschaulicht, in dem neue Color-Objekte erstellt werden, indem bereits vorhandene benutzerdefinierte Farben desselben Typs kopiert werden.
using System;
using System.Collections.Generic;
namespace GangOfFour.Prototype
{
/// <summary>
/// MainApp startup class for Real-World
/// Prototype Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
ColorManager colormanager = new ColorManager();
// Initialize with standard colors
colormanager["red"] = new Color(255, 0, 0);
colormanager["green"] = new Color(0, 255, 0);
colormanager["blue"] = new Color(0, 0, 255);
// User adds personalized colors
colormanager["angry"] = new Color(255, 54, 0);
colormanager["peace"] = new Color(128, 211, 128);
colormanager["flame"] = new Color(211, 34, 20);
// User clones selected colors
Color color1 = colormanager["red"].Clone() as Color;
Color color2 = colormanager["peace"].Clone() as Color;
Color color3 = colormanager["flame"].Clone() as Color;
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
class Color : ColorPrototype
{
private int _red;
private int _green;
private int _blue;
// Constructor
public Color(int red, int green, int blue)
{
this._red = red;
this._green = green;
this._blue = blue;
}
// Create a shallow copy
public override ColorPrototype Clone()
{
Console.WriteLine(
"Cloning color RGB: {0,3},{1,3},{2,3}",
_red, _green, _blue);
return this.MemberwiseClone() as ColorPrototype;
}
}
/// <summary>
/// Prototype manager
/// </summary>
class ColorManager
{
private Dictionary<string, ColorPrototype> _colors =
new Dictionary<string, ColorPrototype>();
// Indexer
public ColorPrototype this[string key]
{
get { return _colors[key]; }
set { _colors.Add(key, value); }
}
}
}
Ausgabe:
Klonfarbe RGB: 255, 0, 0
Klonierungsfarbe RGB: 128,211,128
Klonierungsfarbe RGB: 211, 34, 20
Abstraktes Fabrikmuster
Bieten Sie eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte, ohne deren konkrete Klassen anzugeben.
In diesem Beispiel wird die Erstellung verschiedener Tierwelten für ein Computerspiel anhand verschiedener Fabriken veranschaulicht. Obwohl die von den Kontinentfabriken geschaffenen Tiere unterschiedlich sind, bleiben die Interaktionen zwischen den Tieren gleich.
using System;
namespace GangOfFour.AbstractFactory
{
/// <summary>
/// MainApp startup class for Real-World
/// Abstract Factory Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
public static void Main()
{
// Create and run the African animal world
ContinentFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld(africa);
world.RunFoodChain();
// Create and run the American animal world
ContinentFactory america = new AmericaFactory();
world = new AnimalWorld(america);
world.RunFoodChain();
// Wait for user input
Console.ReadKey();
}
}
/// <summary>
/// The 'AbstractFactory' abstract class
/// </summary>
abstract class ContinentFactory
{
public abstract Herbivore CreateHerbivore();
public abstract Carnivore CreateCarnivore();
}
/// <summary>
/// The 'ConcreteFactory1' class
/// </summary>
class AfricaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Wildebeest();
}
public override Carnivore CreateCarnivore()
{
return new Lion();
}
}
/// <summary>
/// The 'ConcreteFactory2' class
/// </summary>
class AmericaFactory : ContinentFactory
{
public override Herbivore CreateHerbivore()
{
return new Bison();
}
public override Carnivore CreateCarnivore()
{
return new Wolf();
}
}
/// <summary>
/// The 'AbstractProductA' abstract class
/// </summary>
abstract class Herbivore
{
}
/// <summary>
/// The 'AbstractProductB' abstract class
/// </summary>
abstract class Carnivore
{
public abstract void Eat(Herbivore h);
}
/// <summary>
/// The 'ProductA1' class
/// </summary>
class Wildebeest : Herbivore
{
}
/// <summary>
/// The 'ProductB1' class
/// </summary>
class Lion : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Wildebeest
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
/// <summary>
/// The 'ProductA2' class
/// </summary>
class Bison : Herbivore
{
}
/// <summary>
/// The 'ProductB2' class
/// </summary>
class Wolf : Carnivore
{
public override void Eat(Herbivore h)
{
// Eat Bison
Console.WriteLine(this.GetType().Name +
" eats " + h.GetType().Name);
}
}
/// <summary>
/// The 'Client' class
/// </summary>
class AnimalWorld
{
private Herbivore _herbivore;
private Carnivore _carnivore;
// Constructor
public AnimalWorld(ContinentFactory factory)
{
_carnivore = factory.CreateCarnivore();
_herbivore = factory.CreateHerbivore();
}
public void RunFoodChain()
{
_carnivore.Eat(_herbivore);
}
}
}
Ausgabe:
Löwe isst Gnus
Wolf isst Bison