C# Language
창조적 인 디자인 패턴
수색…
비고
창조적 인 패턴은 시스템을 객체가 어떻게 생성되고, 구성되고, 표현되는지를 분리하는 것을 목표로합니다. 객체 생성의 대상, 대상, 방법 및 시점에 따라 시스템의 유연성이 향상됩니다. 창조적 인 패턴은 시스템이 사용하는 클래스에 대한 지식을 캡슐화하지만, 이들 클래스의 인스턴스가 어떻게 생성되고 결합되는지에 대한 세부 사항을 숨 깁니다. 프로그래머들은 상속 시스템을 구성하면 시스템이 너무 경직된다는 것을 깨닫게되었습니다. 창조 패턴은이 가까운 결합을 깨기 위해 고안되었습니다.
싱글 톤 패턴
싱글 톤 패턴은 클래스 생성을 정확히 하나의 단일 인스턴스로 제한하도록 설계되었습니다.
이 패턴은 다음 중 하나만있는 시나리오에서 사용됩니다.
- 다른 객체의 상호 작용을 조율하는 단일 클래스, 예. 관리자 클래스
- 고유 한 단일 리소스를 나타내는 하나의 클래스, 예 : 로깅 구성 요소
Singleton 패턴을 구현하는 가장 일반적인 방법 중 하나는 CreateInstance()
또는 GetInstance()
(또는 C #, Instance
의 정적 속성 GetInstance()
와 같은 정적 팩터 리 메서드를 사용 하는 것입니다. 그러면이 Instance
는 항상 동일한 인스턴스를 반환하도록 설계됩니다.
메서드 또는 속성에 대한 첫 번째 호출은 Singleton 인스턴스를 만들고 반환합니다. 그런 다음 메서드는 항상 동일한 인스턴스를 반환합니다. 이렇게하면 싱글 톤 객체의 인스턴스가 하나만 존재합니다.
new
를 통한 인스턴스 생성을 방지하려면 클래스 생성자를 private.
로 만들어야합니다 private.
다음은 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;
}
}
}
이 패턴을 자세히 설명하기 위해 아래 코드는 Instance 속성이 두 번 이상 호출 될 때 Singleton의 동일한 인스턴스가 반환되는지 여부를 확인합니다.
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");
}
}
}
주 :이 구현은 thread 세이프가 아닙니다.
이 스레드로부터 안전하게 만드는 방법을 포함하여 더 많은 예제를 보려면 Singleton Implementation을 방문하십시오.
싱글 톤은 개념적으로 글로벌 값과 유사하며 유사한 디자인 결함과 우려를 일으 킵니다. 이 때문에 싱글 톤 패턴은 널리 안티 패턴으로 간주됩니다.
"싱글턴에 관해서 나쁘지 않은가?" 사용시 발생하는 문제에 대한 자세한 내용은
C #에서는 클래스를 static
으로 만들어 모든 멤버를 정적으로 만들 수 있으며 클래스를 인스턴스화 할 수 없습니다. 이 점을 감안할 때, 싱글 톤 패턴 대신 정적 클래스를 사용하는 것이 일반적입니다.
두 가지 주요 차이점에 대해서는 C # Singleton Pattern vs. Static Class를 참조하십시오 .
공장 방법 패턴
공장 방식은 창조적 인 디자인 패턴 중 하나입니다. 정확한 결과 유형을 지정하지 않고 객체를 만드는 문제를 처리하는 데 사용됩니다. 이 문서는 Factory Method DP를 올바르게 사용하는 방법을 알려줍니다.
간단한 예를 들어 당신에게 그 아이디어를 설명해 드리겠습니다. 전류계, 전압계 및 저항계의 세 가지 유형의 장치를 생산하는 공장에서 일하고 있다고 가정 해보십시오. 선택한 장치를 만들 수있는 중앙 컴퓨터 용 프로그램을 작성하고 있지만 보스의 생산 결정에 대해서는 최종 결정을 모릅니다.
모든 장치가 가지고있는 몇 가지 공통적 인 기능을 가진 인터페이스 IDevice
장치를 만들어 보겠습니다.
public interface IDevice
{
int Measure();
void TurnOff();
void TurnOn();
}
이제 디바이스를 나타내는 클래스를 생성 할 수 있습니다. 이러한 클래스는 IDevice
인터페이스를 구현해야합니다.
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..."); }
}
이제 factory 메소드를 정의해야합니다. static 메소드를 내부에 가진 DeviceFactory
클래스를 생성 DeviceFactory
봅시다 :
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();
}
}
}
큰! 코드를 테스트 해 봅시다.
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();
}
}
다음은이 코드를 실행 한 후 표시되는 출력 예입니다.
AmMeter가 켜지면 ...
36
6
33
43
24
AmMeter가 작별 인사를하는 등 깜박입니다!
VoltMeter가 켜짐 ...
102
-61
85
138
36
VoltMeter가 작별 인사를하는 등 깜박입니다!
OhmMeter가 켜집니다 ...
723828
368536
685412
800266
578595
OhmMeter가 작별 인사를하는 등 깜박입니다!
작성자 패턴
동일한 구성 프로세스가 서로 다른 표현을 생성 할 수 있도록 복잡한 객체의 구조를 표현과 분리하고 객체의 어셈블리에 대한 높은 수준의 제어를 제공합니다.
이 예제에서는 다른 차량이 단계적으로 조립되는 Builder 패턴을 보여줍니다. Shop은 VehicleBuilders를 사용하여 일련의 순차적 인 단계로 다양한 차량을 구성합니다.
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"]);
}
}
}
산출
차량 종류 : 스쿠터 프레임 : 스쿠터 프레임
엔진 : 없음
# 바퀴 : 2
#Doors : 0차량 유형 : 자동차
프레임 : 자동차 프레임
엔진 : 2500 cc
# 바퀴 : 4
#Doors : 4차량 유형 : MotorCycle
프레임 : 모터 사이클 프레임
엔진 : 500cc
# 바퀴 : 2
#Doors : 0
프로토 타입 패턴
프로토 타입 인스턴스를 사용하여 만들 개체의 종류를 지정하고이 프로토 타입을 복사하여 새 개체를 만듭니다.
이 예제에서는 동일한 유형의 기존 사용자 정의 색상을 복사하여 새 Color 객체를 만드는 프로토 타입 패턴을 보여줍니다.
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); }
}
}
}
산출:
클론 색상 RGB : 255, 0, 0
클론 색상 RGB : 128,211,128
클론 색상 RGB : 211, 34, 20
추상 공장 패턴
구체적인 클래스를 지정하지 않고 관련 객체 또는 종속 객체의 패밀리를 작성하기위한 인터페이스를 제공합니다.
이 예제에서는 서로 다른 팩토리를 사용하는 컴퓨터 게임을위한 서로 다른 동물 세계를 만드는 방법을 보여줍니다. 대륙 공장에서 만든 동물은 다르지만 동물 간의 상호 작용은 동일합니다.
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);
}
}
}
산출:
사자가 Wildebeest를 먹는다.
늑대는 들소를 먹는다.