PlantUMLでデザインパターンのクラス図を描く
GoFのデザインパターンは23種類もあるので、PlantUMLでクラス図を書く練習にちょうどよい。 そういう訳で、PlantUMLでデザインパターンのクラス図を描く。
その前に、用語を整理しておこう。
UML では、用途に応じて図が何種類か定義されている。クラス図(Class Diagram)はそのうちの1つだ。
PlantUML はこれを書くためのツールで、jarとして端末から実行する。IntelliJ IDEA や Visual Studio Code といった IDE で使えるプラグインもあり、esa.io や Confluence のような情報共有ツール上でも利用できるので、好きな環境でやろう。
こういうテキストを書いておくと、
@startuml class ClassA { } class ClassB { } @enduml
こういう図が出力される。
図を書く際は、ここから PlantUML Language Reference Guide をダウンロードしてこれを見ながらやることになる。なんと、日本語訳されたバージョンもある。
デザインパターン)は、JavaやC++に頻出のクラスの設計に名前が付けられたもので、次の本が詳しい。
古いC++使ってる人は次の本(結城さんの本のネタ元だ)でもいいかもしれない。
私はどちらも持ってるが、わかりやすいのは1冊目だった。
クラス図
01. Iteratorパターン
@startuml interface Aggregate { {abstract} iterator() } interface Iterator { {abstract} hasNext() {abstract} next() } class ConcreteAggregate { iterator() } class ConcreteIterator { aggregate hasNext() next() } Aggregate -right-> Iterator : Creates > ConcreteAggregate .up.|> Aggregate ConcreteIterator o-left-> ConcreteAggregate ConcreteIterator .up.|> Iterator @enduml
02. Adapterパターン
継承を用いたAdapterパターン
@startuml class Client interface Target { {abstract} targetMethod1() {abstract} targetMethod2() } class Adapter { targetMethod1() targetMethod2() } class Adaptee { methodA() methodB() methodC() } Client -down-> Target : Uses > Target <|.right. Adapter : implements < Adapter -right-|> Adaptee : extends > @enduml
委譲を用いたAdapterパターン
@startuml class Client abstract Target { {abstract} targetMethod1() {abstract} targetMethod2() } class Adapter { adaptee targetMethod1() targetMethod2() } class Adaptee { methodA() methodB() methodC() } Client -down-> Target : Uses > Target <|-right- Adapter : extends < Adapter o-right-> Adaptee : has > @enduml
03. Template Method パターン
@startuml abstract AbstractClass { abstract method1() abstract method2() abstract method3() abstract templateMethod() } class ConcreteClass { method1 method2 method3 } ConcreteClass -up-|> AbstractClass @enduml
04. Factory Method パターン
@startuml package "フレームワーク" { abstract Creator { create() {abstract} factoryMethod() } abstract Product { {abstract} method1() {abstract} method2() {abstract} method3() } } package "具体的な肉付け" { class ConcreteCreator { factoryMethod } class ConcreteProduct { method1() method2() method3() } } Creator -right-> Product : Creates > ConcreteCreator -right-> ConcreteProduct : Creates > ConcreteCreator -up-|> Creator ConcreteProduct -up-|> Product
05. Singletonパターン
@startuml class Singleton { {static} -singleton -Singleton() {static} +getInstance() } @enduml
06. Prototypeパターン
@startuml class Client { } abstract Prototype{ {abstract} createClone() } class ConcretePrototype { createClone() } Client -right-> Prototype : Uses > ConcretePrototype -up-|> Prototype @enduml
07. Builderパターン
@startuml class Director { builder construct() } class Builder { buildPart() } class ConcreteBuilder { buildPart() getResult() : Product } class Product { } Director o-> Builder Builder <|- ConcreteBuilder ConcreteBuilder --> Product : Creates > @enduml
08. Abstract Factoryパターン
@startuml package "factory" { abstract AbstractProduct1 { {abstract} executeA() {abstract} executeB() } abstract AbstractProduct2 { {abstract} doAlpha() {abstract} doBeta() } abstract AbstractProduct3 { {abstract} performOne() {abstract} performTwo() } abstract AbstractFactory { {abstract} createProduct1() {abstract} createProduct2() {abstract} createProduct3() } AbstractFactory -up-> AbstractProduct1 : Creates > AbstractFactory -up-> AbstractProduct2 : Creates > AbstractFactory -up-> AbstractProduct3 : Creates > } package "concretefactory" { class ConcreteProduct1 { executeA() executeB() } class ConcreteProduct2 { doAlpha() doBeta() } class ConcreteProduct3 { performOne() performTwo() } class ConcreteFactory { createProduct1() createProduct2() createProduct3() } ConcreteFactory -up-> ConcreteProduct1 : Creates > ConcreteFactory -up-> ConcreteProduct2 : Creates > ConcreteFactory -up-> ConcreteProduct3 : Creates > } ConcreteProduct1 -left-|> AbstractProduct1 ConcreteProduct2 -left-|> AbstractProduct2 ConcreteProduct3 -left-|> AbstractProduct3 ConcreteFactory -left-|> AbstractFactory @enduml
09. Bridgeパターン
@startuml class Abstraction { impl method1() method2() method3() } abstract Implementor { {abstract} implMethodX() {abstract} implMethodY() } class RefinedAbstraction { refinedMethodA() refinedMethodB() } class ConcreteImplementor { implMethodX() implMethodY() } RefinedAbstraction -up-|> Abstraction ConcreteImplementor -up-|> Implementor Abstraction o-right-> Implementor note left of Abstraction::method1 This method uses impl's method end note @enduml
10. Strategyパターン
@startuml class Context { strategy contextMethod() } abstract Strategy { {abstract} strategyMethod() } class ConcreteStrategy1 { strategyMethod() } class ConcreteStrategy2 { strategyMethod() } Context o-right-> Strategy ConcreteStrategy1 -up-|> Strategy ConcreteStrategy2 -up-|> Strategy @enduml
11. Compositeパターン
@startuml class Client { } abstract Component { {abstract} method1() {abstract} method2() add() remove() getChild() } class Leaf { method1() method2() } class Composite { children method1() method2() add() remove() getChild() } Client -right-> Component : Uses > Leaf -up-|> Component Composite -up-|> Component Composite o-up-> Component @enduml
12. Decoratorパターン
@startuml abstract Component { {abstract} method1() {abstract} method2() {abstract} method3() } class ConcreteComponent { method1() method2() method3() } class Decorator { component } class ConcreteDecorator { method1() method2() method3() } ConcreteComponent -up-|> Component Decorator -up-|> Component Decorator o-up-> Component ConcreteDecorator -up|> Decorator @enduml
13. Visitorパターン
@startuml abstract Visitor { {abstract} visit(ConcreteElementA) {abstract} visit(ConcreteElementB) } class ConcreteVisitor { visit(ConcreteElementA) visit(ConcreteElementB) } ConcreteVisitor -up-|> Visitor abstract Element { {abstract} accept() } class ConcreteElementA { accept() } class ConcreteElementB { accept() } class ObjectStructure ConcreteElementA -up-|> Element ConcreteElementB -up-|> Element ObjectStructure o-left-> Element @enduml
14. Chain Of Responsibilityパターン
@startuml class Client abstract Handler Handler : next Handler : {abstract} request() class ConcreteHandler1 ConcreteHandler1 : request() class ConcreteHandler2 ConcreteHandler2 : request() Client -right-> Handler : Request > Handler o-right-> Handler ConcreteHandler1 -up-|> Handler ConcreteHandler2 -up-|> Handler @enduml
15. Facadeパターン
@startuml class Client class Facade class ClassA class ClassB class ClassC class ClassD Client -down-> Facade : Uses > Facade -down-> ClassA Facade -down-> ClassB Facade -down-> ClassC Facade -down-> ClassD ClassA -down-> ClassB ClassB -right-> ClassC ClassC -left-> ClassB ClassD -down-> ClassC @enduml
16. Mediatorパターン
@startuml abstract Mediator { {abstract} createColleagues() {abstract} colleagueChanged() } abstract Colleague { mediator {abstract} setMediator() {abstract} controlColleague() } class ConcreteMediator { concreteColleague1 concreteColleague2 concreteColleague3 createColleagues() colleagueChanged() } class ConcreteColleague1 { controlColleague() } class ConcreteColleague2 { controlColleague() } class ConcreteColleague3 { controlColleague() } ConcreteMediator -up-|> Mediator Colleague o-left-> Mediator ConcreteColleague1 -up-|> Colleague ConcreteColleague2 -up-|> Colleague ConcreteColleague3 -up-|> Colleague ConcreteMediator o-up-> ConcreteColleague1 ConcreteMediator o-up-> ConcreteColleague2 ConcreteMediator o-up-> ConcreteColleague3 @enduml
17. Mementoパターン
@startuml class Caretaker class Originator { createMemento() restoreMemento() } class Memento <<wide interface>> <<narrow interface>> { ~getProtectedInfo +getPublicInfo } Caretaker -right-> Originator : Requests > Caretaker o-down-> Memento Originator -down-> Memento : Creates > @enduml
18. Observerパターン
@startuml abstract Subject { observers addObserver() deleteObserver() notifyObserver() {abstract} getSubjectStatus() } abstract Observer { {abstract} update() } class ConcreteSubject { getSubjecdtStatus() } class ConcreteObserver { update() } Subject o-right-> Observer : Notifies > ConcreteSubject -up-|> Subject ConcreteObserver -up-|> Observer @enduml
19. Stateパターン
@startuml class Context { state requestX() requestY() requestZ() } abstract State { methodA() methodB() methodC() methodD() } class ConcreteState1 { methodA() methodB() methodC() methodD() } class ConcreteState2 { methodA() methodB() methodC() methodD() } Context o-right-> State ConcreteState1 -up-|> State ConcreteState2 -up-|> State @enduml
20. Flyweightパターン
@startuml class Flyweight { methodA() methodB() } class FlyweightFactory { pool getFlyweight() } class Client { } FlyweightFactory o-up-> Flyweight : Creates > Client -up-> FlyweightFactory : Uses > Client --up--> Flyweight : Uses > @enduml
21. Proxyパターン
@startuml class Client abstract Subject { request1() request2() request3() } class Proxy { realSubject request1() request2() request3() } class RealSubject { request1() request2() request3() } Client o-right-> Subject : Uses > Proxy -up-|> Subject RealSubject -up-|> Subject Proxy o-right-> RealSubject : Uses > @enduml
22. Commandパターン
@startuml class Command { execute() } class Invoker { } class Receiver { action() } class ConcreteCommand { receiver execute() } class Client { } Invoker o-left-> Command ConcreteCommand -up-|> Command ConcreteCommand o-left-> Receiver Client -up-> ConcreteCommand : Creates < @enduml
23. Interpreterパターン
@startuml class Client { } class Context { getInfoToInterpret() } abstract AbstractExpression { {abstract} interpret() } class TerminalExpression { interpret() } class NonterminalExpression { childExpressions interpret() } Client -left-> Context : Creates > Client -right-> AbstractExpression : Uses > TerminalExpression -up-|> AbstractExpression NonterminalExpression -up-|> AbstractExpression NonterminalExpression o--> AbstractExpression @enduml
感想
23つの中で私が好きなのはTemplate MethodパターンとBridgeパターンだが、もしもこれに名前がついてなかったら、
- 「親クラスのメソッドから、子クラスで定義されるメソッドを呼び出すやつ」
- 「コンストラクタで実装を渡すやつ」
という冗長な名前で呼ばれるか、もしくは、職場の誰かの名前か地名がついて
- 「伊藤パターン」
- 「銀座パターン」
とか呼ばれ、その結果レビューが意味不明になったろうなあと思っている。