GoFのデザインパターン23種類をC#で書いたまとめ記事です。
本記事はGang of Fourの「オブジェクト指向における再利用のためのデザインパターン」で紹介されている23種類のデザインパターンを参考に、最小構成のC#サンプルコードを列挙しています。 どのデザインパターンを適用するか悩んだ際など、自由にご利用ください。
なお免責として、自分の理解の範囲なので悪しからず。内容に関する指摘は歓迎です。
デザインパターンと直接関係していないクラスや関数・変数に関しては、Some~, Hoge, Foo等の言葉を用いて表しています。
http://amazon.co.jp/オブジェクト指向における再利用のためのデザインパターン-エリック-ガンマ/dp/4797311126amazon.co.jp
- Abstract Factory
- Builder
- Factory Method
- Prototype
- Singleton
- Adapterパターン
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Abstract Factory
Factory
public abstract class AbstractFactory { public abstract Product CreateProduct(); } public class ConcreteFactory1 : AbstractFactory { public override Product CreateProduct() { return new ProductA(); } } public class ConcreteFactory2 : AbstractFactory { public override Product CreateProduct() { return new ProductB(); } }
Product
public abstract class Product { } public class ProductA : Product { } public class ProductB : Product { }
Some Application
public class SomeApplication { private Product product; public void Init(AbstractFactory factory) { this.product = factory.CreateProduct(); } } public class SomeApplicationUser { public void SomeFunction(bool someCondition) { var someApp = new SomeApplication(); if (someCondition) { var factory1 = new ConcreteFactory1(); someApp.Init(factory1); } else { var factory2 = new ConcreteFactory2(); someApp.Init(factory2); } } }
Builder
Result
public class Result { public void AddFoo() { } public void RemoveFoo() { } public void SetBar(int someParam) { } }
Builder
public abstract class Builder { public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract void BuildPartC(); public abstract Result GetResult(); } public class ConcreteBuilder : Builder { private Result result = null; public ConcreteBuilder() { this.result = new Result(); } public override void BuildPartA() { this.result.AddFoo(); } public override void BuildPartB() { this.result.AddFoo(); this.result.SetBar(0); } public override void BuildPartC() { this.result.RemoveFoo(); this.result.SetBar(1); } public override Result GetResult() { return result; } }
Director
public class Director { public void Construct(Builder builder) { builder.BuildPartA(); builder.BuildPartB(); } public void ConstructHoge(Builder builder) { builder.BuildPartB(); builder.BuildPartC(); } public void ConstructHuga(Builder builder) { builder.BuildPartA(); builder.BuildPartB(); builder.BuildPartC(); } }
Some Application
public class SomeApplication { public void SomeFunction(int someCondition) { var builder = new ConcreteBuilder(); var director = new Director(); switch (someCondition) { case 1: director.Construct(builder); break; case 2: director.ConstructHoge(builder); break; case 3: director.ConstructHuga(builder); break; } var result = builder.GetResult(); } }
Factory Method
・抽象クラスが、具象クラスによって決定されるインスタンスに興味がないとき
・具象クラスにインスタンスを作らせ、抽象クラスではそのインタフェース(抽象クラス)のみを扱う
最もシンプルな実装
Product
public abstract class Product { } public class ProductA : Product { } public class ProductB : Product { }
Product User
public abstract class ProductUser { private Product product = null; // factory method protected abstract Product CreateProduct(); public ProductUser() { // you should not call CreateProduct() here. // because you still cannot use concrete CreateProduct() in super class constructor. } public void LazyInit() { this.product = CreateProduct(); } public void SomeFunction() { } } public class ConcreteProductUser1 : ProductUser { protected override Product CreateProduct() { return new ProductA(); } } public class ConcreteProductUser2 : ProductUser { protected override Product CreateProduct() { return new ProductB(); } }
Some Application
public class SomeApplication { public void SomeFunction(bool someCondition) { if (someCondition) { var user1 = new ConcreteProductUser1(); user1.LazyInit(); user1.SomeFunction(); } else { var user2 = new ConcreteProductUser2(); user2.LazyInit(); user2.SomeFunction(); } } }
テンプレートを使う場合
public class StandartProductUser<T> : ProductUser where T : Product, new() { protected override Product CreateProduct() { return new T(); } }
public class SomeApplication { public void SomeFunction(bool someCondition) { if (someCondition) { var user1 = new StandartProductUser<ProductA>(); user1.LazyInit(); user1.SomeFunction(); } else { var user2 = new StandartProductUser<ProductB>(); user2.LazyInit(); user2.SomeFunction(); } } }
Prototype
Product
public class Product { public void Init(int someParam) { } public virtual Product Clone() { return (Product)MemberwiseClone(); } } public class ProductB : Product { public override Product Clone() { return (Product)MemberwiseClone(); } }
Prototype Factory
public class PrototypeFactory { private Product prototypeProduct = null; public PrototypeFactory(Product prototype) { this.prototypeProduct = prototype; } public Product MakeProduct1() { var product = this.prototypeProduct.Clone(); product.Init(1); return product; } public Product MakeProduct2() { var product = this.prototypeProduct.Clone(); product.Init(2); return product; } }
Some Application
public class SomeApplication { public void SomeFunction(bool someCondition) { Product prototype; if (someCondition) { prototype = new Product(); } else { prototype = new ProductB(); } var factory = new PrototypeFactory(prototype); var product1 = factory.MakeProduct1(); var product2 = factory.MakeProduct2(); } }
Singleton
public class Singleton { private static Singleton instance = null; public static Singleton Instance { get { if (instance == null) instance = new Singleton(); return instance; } } protected Singleton() { } }
Adapterパターン
- 既存クラスを利用したいが、インタフェースが合わない
Class Adapter
public class Adaptee { public void HugaFunction() { } } public interface Target { public void HogeFunction(); } public class Adapter : Adaptee, Target { public void HogeFunction() { this.HogeFunction(); } }
Object Adapter
public class Adaptee { public void HugaFunction() { } } public class Target { public virtual void HogeFunction() { } } public class Adapter : Target { private Adaptee adaptee = null; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public override void HogeFunction() { adaptee.HugaFunction(); } }
Bridge
- ネストされた継承を解消したい
- 実装の変更に依存させない
- 実装をサブクラスの追加により拡張可能にすべき
Implementor
public abstract class Implementor { public abstract void SomeFunctionImp(); } public class ConcreteImplementorA : Implementor { public override void SomeFunctionImp() { } } public class ConcreteImplementorB : Implementor { public override void SomeFunctionImp() { } }
Abstraction
public abstract class Abstraction { private Implementor imp = null; public Abstraction(Implementor implementor) { this.imp = implementor; } public void SomeFunction() { this.imp.SomeFunctionImp(); } } public class RefinedAbstraction : Abstraction { public RefinedAbstraction(Implementor implementor) : base(implementor) { } public void SomeRefinedFunction() { SomeFunction(); SomeFunction(); } }
Composite
- 木構造を表現できる
Component
public abstract class Component { public virtual void Add(Component component) { } public virtual void Remove(Component component) { } public virtual Component GetChild(int index) { return null; } public abstract void Operation(); }
Composite, Leaf
using System.Collections.Generic; public class Composite : Component { private List<Component> children = null; public Composite() { this.children = new List<Component>(); } public override void Add(Component component) { children.Add(component); } public override void Remove(Component component) { children.Remove(component); } public override Component GetChild(int index) { if (index < children.Count) { return children[index]; } return null; } public override void Operation() { foreach (var child in children) { child.Operation(); } } } public class Leaf : Component { public override void Operation() { } }
Decorator
Component
public abstract class Component { public abstract void Operation(); } public class ConcreteComponent : Component { public override void Operation() { } }
Decorator
public abstract class Decorator : Component { private Component component; public Decorator(Component component) { this.component = component; } public override void Operation() { component.Operation(); } } public class ConcreteDecoratorA : Decorator { private int someParam; public ConcreteDecoratorA(Component component) : base(component) { } public override void Operation() { base.Operation(); } } public class ConcreteDecoratorB : Decorator { public ConcreteDecoratorB(Component component) : base(component) { } public override void Operation() { base.Operation(); SomeFunction(); } public void SomeFunction() { } }
SomeApplication
public class SomeApplication { public void SomeFunction() { Component comp = new ConcreteComponent(); Component deco1 = new ConcreteDecoratorA(comp); Component deco2 = new ConcreteDecoratorB(comp); Component deco3 = new ConcreteDecoratorA(new ConcreteDecoratorB(comp)); Component deco4 = new ConcreteDecoratorA(new ConcreteDecoratorB(new ConcreteDecoratorB(comp))); } }
Facade
・サブシステムの構成要素を隠ぺい及び結合を弱める
Facade
using SomeSubSystems; public class Facade { public void SomeFunction() { var subSystemA = new SubSystemA(); var subSystemB = new SubSystemB(); var subSystemC = new SubSystemC(); subSystemA.FunctionA(); subSystemB.FunctionB(); subSystemC.FunctionC(); } }
namespace SomeSubSystems { public class SubSystemA { public void FunctionA() { } } public class SubSystemB { public void FunctionB() { } } public class SubSystemC { public void FunctionC() { } } }
Flyweight
public abstract class Flyweight { public abstract void Operation(ExtrinsicState extrinsicState); } public class ConcreteFlyweight : Flyweight { private int someIntrinsicState; public override void Operation(ExtrinsicState extrinsicState) { } } public class UnsharedConcreteFlyweight : Flyweight { private int allState; public override void Operation(ExtrinsicState extrinsicState) { } }
ExtrinsicState
public class ExtrinsicState { public int someParam; }
FlyweightFactory
using System.Collections.Generic; public class FlyweightFactory { private Dictionary<string, ConcreteFlyweight> flyweights; public FlyweightFactory() { flyweights = new Dictionary<string, ConcreteFlyweight>(); } public ConcreteFlyweight CreateConcreteFlyweight(string key) { if (!flyweights.ContainsKey(key)) { flyweights.Add(key, new ConcreteFlyweight()); } return flyweights[key]; } public UnsharedConcreteFlyweight CreateUnsharedConcreteFlyweight() { return new UnsharedConcreteFlyweight(); } }
Some Application
public class SomeApplication { public void SomeFuncition() { var factory = new FlyweightFactory(); var exState = new ExtrinsicState(); for (int i = 0; i < 100; i++) { // create 100 foo var concreteFlyweight = factory.CreateConcreteFlyweight("foo"); exState.someParam = i; concreteFlyweight.Operation(exState); } for (int i = 0; i < 30; i++) { // create 30 bar var concreteFlyweight = factory.CreateConcreteFlyweight("bar"); exState.someParam = i; concreteFlyweight.Operation(exState); } var unsharedFlyweight = factory.CreateUnsharedConcreteFlyweight(); unsharedFlyweight.Operation(exState); } }
Proxy
Subject
public abstract class Subject { public abstract void Request(); } public class RealSubject : Subject { public override void Request() { } }
public class Proxy : Subject { RealSubject realSubject = null; public override void Request() { // you can manage how to access here realSubject.Request(); } }
Chain of Responsibility
・受け手を明確にせずに、複数あるオブジェクトの1つに対して要求を発行したい
Handler
public abstract class Handler { protected Handler successor; public virtual void HandleRequest() { if (successor != null) { successor.HandleRequest(); } } } public class ConcreteHandler1 : Handler { public override void HandleRequest() { base.HandleRequest(); } } public class ConcreteHandler2 : Handler { public override void HandleRequest() { System.Console.WriteLine("some customized handle"); } }
SomeApplication
public class SomeApplication { public void SomeFunction() { var handler1 = new ConcreteHandler1(); var handler2 = new ConcreteHandler2(); handler1.HandleRequest(); } }
Command
Command
public abstract class Command { public abstract void Execute(); } public class ConcreteCommand : Command { private int someState; Receiver receiver = null; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } public override void Execute() { receiver.SomeAction(); } }
Receiver
public class Receiver { public void SomeAction() { } }
public class SomeApplication { private List<Command> commandList = null; private int currentIndex = 0; public void SomeFunction() { this.commandList = new List<Command>(); var receiver1 = new Receiver(); var command1 = new ConcreteCommand(receiver1); commandList.Add(command1); var receiver2 = new Receiver(); var command2 = new ConcreteCommand(receiver2); commandList.Add(command2); } public void ExecuteNext() { commandList[currentIndex].Execute(); currentIndex++; } }
Interpreter
- 単純な文法の言語を解釈する
using System; public abstract class AbstractExpression { public abstract void Interpret(Context context); } public class TerminalExpression : AbstractExpression { private string literal; public TerminalExpression(string literal) { this.literal = literal; } public override void Interpret(Context context) { // some interpret Console.Write(this.literal); } } public class NonterminalExpression : AbstractExpression { private TerminalExpression exp1; private TerminalExpression exp2; public NonterminalExpression(TerminalExpression exp1, TerminalExpression exp2) { this.exp1 = exp1; this.exp2 = exp2; } public override void Interpret(Context context) { // some interpret Console.Write(this.exp1 + "&" + this.exp2); } }
Context
public class Context { public string SomeInfo; }
Client
public class Client { public void SomeFunction() { var terminalExp1 = new TerminalExpression("literal1"); var terminalExp2 = new TerminalExpression("literal2"); var someExp = new NonterminalExpression(terminalExp1, terminalExp2); var context = new Context { SomeInfo = "someINfo" }; someExp.Interpret(context); } }
Iterator
Aggregate
public abstract class Aggregate { public abstract Iterator CreateIterator(); } public class ConcreteAggregate : Aggregate { public override Iterator CreateIterator() { return new ConcreteIterator(this); } }
public abstract class Iterator { protected Aggregate aggregate; public Iterator(Aggregate aggregate) { this.aggregate = aggregate; } public abstract void First(); public abstract void Next(); public abstract bool IsDone(); public abstract SomeItem CurrentItem(); } public class ConcreteIterator : Iterator { private int currentIndex = 0; public ConcreteIterator(Aggregate aggregate) : base(aggregate) { } public override void First() { // some algorithm this.currentIndex = 0; } public override void Next() { // some algorithm this.currentIndex++; } public override bool IsDone() { // some algorithm return this.currentIndex < aggregate.Count; } public override SomeItem CurrentItem() { // some algorithm return this.currentIndex[currentIndex]; } }
SomeApplication
public class SomeItem { } public class SomeApplication { private Aggregate someAggregate = null; public void SomeFunction() { var iterator = this.someAggregate.CreateIterator(); iterator.First(); while (!iterator.IsDone()) { iterator.Next(); var item = iterator.CurrentItem(); } } }
Mediator
- 関係性をカプセル化する
Mediator
public abstract class Mediator { public abstract void CreateColleagues(); public abstract void ColleagueChanged(Colleague colleague); } public class ConcreteMediator : Mediator { private ConcreteColleague1 colleague1; private ConcreteColleague2 colleague2; public override void CreateColleagues() { this.colleague1 = new ConcreteColleague1(this); this.colleague2 = new ConcreteColleague2(this); } public override void ColleagueChanged(Colleague colleague) { if (colleague == this.colleague1) { this.colleague1.SetFoo(); } else if (colleague == this.colleague2) { this.colleague2.SetBar(); } } }
Colleague
public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator = mediator; } protected void Changed() { this.mediator.ColleagueChanged(this); } } public class ConcreteColleague1 : Colleague { public ConcreteColleague1(Mediator mediator) : base(mediator) { } public void HogeEvent() { // some event such as mouse click Changed(); } public void SetFoo() { // some action } } public class ConcreteColleague2 : Colleague { public ConcreteColleague2(Mediator mediator) : base(mediator) { } public void HugaEvent() { // some event such as mouse click Changed(); } public void SetBar() { // some action } }
Some Application
public class SomeApplication { public void SomeFunction() { var mediator = new ConcreteMediator(); mediator.CreateColleagues(); } }
Memento
- カプセル化を破壊せずに、ある時点のスナップショットを残しておき、後に復元等で利用する
Memento
public interface IMementoNarrow { } public interface IMementoWide { public void SetState(State state); public State GetState(); } public class Memento : IMementoNarrow, IMementoWide { private State state; public Memento() { } public void SetState(State state) { this.state = state; } public State GetState() { return this.state; } } public class State { // some state params public string someState; }
Originator
public class Originator { public IMementoNarrow CreateMemento() { return new Memento(); } public void SetMemento(IMementoNarrow memento) { var mementoWide = memento as IMementoWide; } public void Foo() { } }
Caretaker
public class Caretaker { private Originator originator; private IMementoNarrow prevMemento; public void SomeExecuteFunction() { // execute something this.originator.Foo(); this.prevMemento = this.originator.CreateMemento(); } public void SomeUndoFunction() { this.originator.SetMemento(this.prevMemento); } }
Observer
Subject
public abstract class Subject { protected List<Observer> observers = null; public virtual void Attach(Observer observer) { this.observers.Add(observer); } public virtual void Detach(Observer observer) { this.observers.Remove(observer); } public virtual void Notify() { foreach (var observer in this.observers) { observer.Update(this); } } } public class ConcreteSubject : Subject { public void Foo() { // do something Notify(); } }
Observer
public abstract class Observer { public abstract void Update(Subject changedSubject); } public class ConcreteObserver : Observer { public override void Update(Subject changedSubject) { // do something update } }
SomeApplication
public class SomeApplication { public void SomeFunction() { var subject = new ConcreteSubject(); subject.Foo(); } }
State
Context
public class Context { private State currentState; public ConcreteStateA stateA { get; private set; } public ConcreteStateB stateB { get; private set; } public Context() { this.stateA = new ConcreteStateA(); this.stateB = new ConcreteStateB(); this.currentState = stateA; } public void Request() { this.currentState.Handle(this); } public void ChangeState(State state) { this.currentState = state; } }
State
public abstract class State { public abstract void Handle(Context context); public virtual void ChangeState(Context context, State state) { context.ChangeState(state); } } public class ConcreteStateA : State { public override void Handle(Context context) { ChangeState(context, context.stateB); } } public class ConcreteStateB : State { public override void Handle(Context context) { ChangeState(context, context.stateA); } }
SomeApplication
public class SomeApplication { public void SomeFunction() { var context = new Context(); context.Request(); } }
Strategy
Context
public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void ContextInterface() { this.strategy.AlgorithmInterface(); } }
Strategy
public abstract class Strategy { public abstract void AlgorithmInterface(); } public class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { // strategy A algorithm } } public class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { // strategy B algorithm } } public class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { // strategy C algorithm } }
SomeApplication
public class SomeApplication { public void SomeFunction() { // when use strategy A { var strategyA = new ConcreteStrategyA(); var context = new Context(strategyA); context.ContextInterface(); } // when use strategy B { var strategyB = new ConcreteStrategyA(); var context = new Context(strategyB); context.ContextInterface(); } // when use strategy C { var strategyC = new ConcreteStrategyA(); var context = new Context(strategyC); context.ContextInterface(); } } }
Template Method
- ハリウッドの原則
public abstract class AbstractClass { public void TemplateMethod() { PrimitiveOperation1(); PrimitiveOperation2(); } protected abstract void PrimitiveOperation1(); protected abstract void PrimitiveOperation2(); } public class ConcreteClass : AbstractClass { protected override void PrimitiveOperation1() { // some first operation } protected override void PrimitiveOperation2() { // some second operation } }
Visitor
- オペレーションをカプセル化する
- 多対多の関係で柔軟
Visitor
public abstract class Visitor { public abstract void VisitConcreteElementA(ConcreteElementA elementA); public abstract void VisitConcreteElementB(ConcreteElementB elementB); } public class ConcreteVisitor1 : Visitor { public override void VisitConcreteElementA(ConcreteElementA elementA) { // some action } public override void VisitConcreteElementB(ConcreteElementB elementB) { // some action } } public class ConcreteVisitor2 : Visitor { public override void VisitConcreteElementA(ConcreteElementA elementA) { // some action } public override void VisitConcreteElementB(ConcreteElementB elementB) { // some action } }
Element
public abstract class Element { public abstract void Accept(Visitor visitor); } public class ConcreteElementA : Element { public override void Accept(Visitor visitor) { visitor.VisitConcreteElementA(this); } } public class ConcreteElementB : Element { public override void Accept(Visitor visitor) { visitor.VisitConcreteElementB(this); } }
Structure
public class ObjectStructure { public IEnumerable<Element> SomeStructure; }
SomeApplication
public class SomeApplication { public void SomeFunction() { var structureA = new ObjectStructure { SomeStructure = new List<ConcreteElementA>().Cast<Element>() }; var structureB = new ObjectStructure { SomeStructure = new List<ConcreteElementB>().Cast<Element>() }; var visitor1 = new ConcreteVisitor1(); var visitor2 = new ConcreteVisitor2(); // when use structureA and visitor1 foreach (var element in structureA.SomeStructure) { element.Accept(visitor1); } // when use structureA and visitor2 foreach (var element in structureA.SomeStructure) { element.Accept(visitor2); } // when use structureB and visitor1 foreach (var element in structureB.SomeStructure) { element.Accept(visitor1); } // when use structureB and visitor2 foreach (var element in structureB.SomeStructure) { element.Accept(visitor2); } } }