Mermaid.jsでデザインパターン全23個のクラス図を書いてみた
結構前ですが、zennがMermaid.jsに対応してましたね。
ちょうど個人的にMermaid.jsでクラス図を書けるようになりたかったので、デザインパターンのクラス図を表現してみることにしました。
『RefactoringGuru』のクラス図を元にしています。
今回記述したコードは全てgithubに上げております。
「デザインパターンの復習とMermaid.jsの学習が一気に出来るのはラッキー!」という気持ちで書いています。
Mermaid.jsを使ってみようかな、と思っている方の参考になると嬉しいです。
ざっくりと書いてしまったので、良い書き方を知っている方がいましたらコメント頂けると嬉しいです!
作ってみた感想
最初にやってみた感想です。
良かった点
- コード化できているので、後から変更がしやすい
- 図をgit管理できるのが良い
- mermaid.jsで何も見なくてもクラス図が書けるようになった
難しい点
- 手や図作成のソフトで書く場合に比べると、細かなニュアンスが出しにくい
- 階層が表しづらい
- 例: 子クラスと孫クラスが横並びになってしまったりする
- 記載する順番によって並び順や矢印の位置が変わってしまう。この辺りをチームで統一するのは難しそう。
- 微妙にかゆい所に手が届かないことがある
- 例: クラスの変数を書く際に、変数の型を記述する形式が無い。
メソッドの返り値の型は指定できる:+createMessage() String
-> 図:+createMessage() : String
変数の型は書いた通りに図に反映される:+String message
-> 図:+String message
- 例: クラスの変数を書く際に、変数の型を記述する形式が無い。
アルファベット順で掲載していきます。
AbstractFactory
複雑なクラス図を書く際は、工夫が必要そうです。
また業務で使うときに考えよう...
classDiagram
class AbstractProductA {
<<abstract>>
}
AbstractProductA <|-- ConcreteProductA1
ConcreteProductA2 --|> AbstractProductA
class AbstractProductB {
<<abstract>>
}
AbstractProductB <|-- ConcreteProductB1
ConcreteProductB2 --|> AbstractProductB
class ConcreteFactory1 {
+createProductA() ProductA
+createProductB() ProductB
}
class AbstractFactory {
<<interface>>
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory2 {
+createProductA() ProductA
+createProductB() ProductB
}
AbstractFactory <|.. ConcreteFactory1
ConcreteFactory2 ..|> AbstractFactory
class Client {
-factory: AbstractFactory
+Client(f: AbstractFactory)
+someOperation()
}
ConcreteFactory1 ..> ConcreteProductB1
ConcreteFactory1 ..> ConcreteProductA1
ConcreteFactory2 ..> ConcreteProductB2
ConcreteFactory2 ..> ConcreteProductA2
Client --> AbstractFactory
Adaptor
classDiagram
direction BT
class Client
class ClientInterface {
<<interface>>
+method(data)
}
class Adapter {
-adaptee: Service
+method(data)
}
class Service {
+serviceMethod(specialData)
}
Client --> ClientInterface: use
Adapter ..|> ClientInterface
Adapter o-->Service
Bridge
classDiagram
direction BT
class Client
class Abstraction {
-i: Implementation
+feature1()
+feature2()
}
class Implementation {
<<interface>>
+method1()
+method2()
+method3()
}
class RefinedAbstraction {
+featureN()
}
class ConcreteImplementations
Client --> Abstraction: use
RefinedAbstraction --|> Abstraction
Abstraction o--> Implementation
ConcreteImplementations ..|> Implementation
Builder
classDiagram
direction BT
class Builder {
<<interface>>
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
}
class ConcreteBuilder1 {
-Product1 result
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
+getResult() Product1
}
class ConcreteBuilder2 {
-Product2 result
+reset()
+buildStepA()
+buildStepB()
+buildStepC()
+getResult() Product2
}
class Director {
-Builder builder
+Director(builder)
+changeBuilder(builder)
+make(type)
}
class Product1
class Product2
Product1 <-- ConcreteBuilder1: create
Product2 <-- ConcreteBuilder2: create
ConcreteBuilder1 ..|> Builder
ConcreteBuilder2 ..|> Builder
Director o--> Builder
ChainOfResponsibility
classDiagram
direction BT
class Handler {
<<interface>>
+setNext(h: Handler)
+handle(request)
}
class BaseHandler {
<<abstract>>
-next: Handler
+setNext(h: Handler)
+handle(request)
}
class ConcreteHandlers {
+handle(request)
}
BaseHandler o--> Handler
BaseHandler ..|> Handler
ConcreteHandlers --|> BaseHandler
Client --> Handler
Command
classDiagram
class Client
class Invoker {
-command
+setCommand(command)
+executeCommand()
}
class Command {
<<interface>>
+execute()
}
class Command1 {
-receiver
-params
+Command1(receiver, params)
+execute()
}
class Command2 {
+execute()
}
class Receiver {
+operation(a, b, c)
}
Invoker --> Command
Command1 ..|> Command
Command1 --> Receiver
Command2 ..|> Command
Client --> Invoker
Client ..> Command1
Client --> Receiver
Composite
classDiagram
direction BT
class Client
class Component {
<<interface>>
+execute()
}
class Leaf {
+execute()
}
class Composite {
-children: Component[]
+add(c: Component)
+remove(c: Component)
+getChildren() Component[]
+execute()
}
Client --> Component: use
Leaf ..|> Component
Composite ..|> Component
Composite o--> Component
Decorator
classDiagram
direction BT
class Client
class Component {
<<interface>>
+execute()
}
class ConcreteComponent {
+execute()
}
class BaseDecorator {
-wrappee: Component
+BaseDecorator(c: Component)
+execute()
}
class ConcreteDecorators {
+execute()
+extra()
}
Client --> Component: use
ConcreteComponent ..|> Component
BaseDecorator ..|> Component
ConcreteDecorators --|> BaseDecorator
BaseDecorator o--> Component
Facade
classDiagram
direction LR
class Client
class Facade {
-linksToSubsystemObjects
-optionalAdditionalFacade
+subsystemOperation()
}
class AdditionalFacade {
+anotherOperation()
}
Client --> Facade
Facade --> AdditionalFacade
FactoryMethod
classDiagram
direction BT
class Creator{
<<abstract>>
+someOperation()
+createProduct()* Product
}
class Product{
<<interface>>
+doStuff()
}
class ConcreteCreatorA{
+createProduct() Product
}
class ConcreteCreatorB{
+createProduct() Product
}
class ConcreteProductA{
}
class ConcreteProductB{
}
ConcreteCreatorA --|> Creator
ConcreteCreatorB --|> Creator
Creator --> Product : Create
ConcreteProductA ..|> Product
ConcreteProductB ..|> Product
Flyweight
classDiagram
direction BT
class FlyweightFactory {
-cache: Flyweight[]
+getFlyweight(repeatingState)
}
class Context {
-uniqueState
-flyweight
+Context(repeatingState, uniqueState)
+operation()
}
class Flyweight {
-repeatingState
+operation(uniqueState)
}
FlyweightFactory o--> Flyweight
Context --> FlyweightFactory
Context --> Flyweight
Client *--> Context
Interpreter
RefactoringGuruにこちらのパターンは記載が無かったため、「Java言語で学ぶデザインパターン入門」を参照しました。
classDiagram
direction LR
class Client
class AbstractExpression {
<<abstract>>
interpret()*
}
class TerminalExpression {
interpret()
}
class NonterminalExpression {
childExpression
interpret()
}
class Context {
getInfoToInterpret()
}
Client o--> Context
Client --> AbstractExpression
NonterminalExpression --|> AbstractExpression
TerminalExpression --|> AbstractExpression
NonterminalExpression o--> AbstractExpression
Iterator
classDiagram
direction BT
class Client
class Iterator {
<<interface>>
+getNext()
+hasMore() bool
}
class IterableCollection {
<<interface>>
+createIterator() Iterator
}
class ConcreteIterator {
-collection: ConcreteCollection
-iterationState
+ConcreteIterator(c: ConcreteCollection)
+getNext()
+hasMore() bool
}
class ConcreteCollection {
+createIterator() Iterator
}
Iterator <-- Client: use
IterableCollection <-- Client: use
ConcreteIterator ..|> Iterator
ConcreteCollection ..|> IterableCollection
ConcreteIterator <--> ConcreteCollection
Mediator
ConcreteMediator ..|> Mediator を間に記載することで、いい感じに配置できました。
classDiagram
direction BT
class Mediator {
<<interface>>
+notify(sender)
}
class ConcreteMediator {
-componentA
-componentB
-componentC
-componentD
+notify(sender)
+reactOnA()
+reactOnB()
+reactOnC()
+reactOnD()
}
class ComponentA {
-m: Mediator
+operationA()
}
class ComponentB {
-m: Mediator
+operationB()
}
class ComponentC {
-m: Mediator
+operationC()
}
class ComponentD {
-m: Mediator
+operationD()
}
ComponentA --> Mediator
ComponentB --> Mediator
ConcreteMediator ..|> Mediator
ComponentC --> Mediator
ComponentD --> Mediator
ConcreteMediator *--> ComponentA
ConcreteMediator *--> ComponentB
ConcreteMediator *--> ComponentC
ConcreteMediator *--> ComponentD
Memento
classDiagram
direction LR
class Originator {
-state
+save() Memento
+restore(m: Memento)
}
class Memento {
-state
-Memento(state)
-getState()
}
class Caretaker {
-originator
-history: Memento[]
+doSomething()
+undo()
}
Originator ..> Memento
Memento <--o Caretaker
Observer
classDiagram
direction LR
class Publisher {
-subscribers: Subscriber[]
-mainState
+subscribe(s: Subscriber)
+unsubscribe(s: Subscriber)
+notifySubscribers()
+mainBusinessLogic()
}
class Subscriber {
<<interface>>
+upgrade(context)
}
class ConcreteSubscribers {
+update(context)
}
class Client
Publisher o--> Subscriber
ConcreteSubscribers ..|> Subscriber
Client --> Publisher
Client ..> ConcreteSubscribers
Prototype
Prototype(基本)
この後、PrototypeパターンでRegisterをもつバージョンのクラス図も載せるので、こちらは基本系としています。
cloneメソッドをサブクラスで実装するシンプルな構成です。
classDiagram
direction BT
class Prototype{
<<interface>>
+clone() Prototype
}
class ConcretePrototype{
-field1
+ConcretePrototype(prototype)
+clone() Prototype
}
class SubclassPrototype{
-field2
+SubclassPrototype(prototype)
+clone() SubclassPrototype
}
class Client
SubclassPrototype --|> ConcretePrototype
ConcretePrototype ..|> Prototype
Client --> Prototype : use
Prototype(レジスター有版)
頻繁に使うインスタンスをレジスターに登録しておき、使うときはレジスターに登録されているインスタンスをcloneして利用する、というPrototypeパターンの拡張版です。
classDiagram
direction BT
class PrototypeRegistry{
- Prototype[] items
+addItem(id: string, p: Prototype)
+getById(id: string) Prototype
+getByColor(color: string) Prototype
}
class Prototype{
<<interface>>
+getColor() string
+clone() Prototype
}
class Button{
-x, y, color
+Button(x, y, color)
+Button(prototype)
+getColor() string
+clone() Prototype
}
class Client
PrototypeRegistry o--> Prototype
Button ..|> Prototype
Client --> PrototypeRegistry : use
Proxy
classDiagram
direction BT
class ServiceInterface {
<<interface>>
+operation()
}
class Proxy {
-realService: Service
+Proxy(s: Service)
+checkAccess()
+operation()
}
class Service {
+operation()
}
Client --> ServiceInterface
Proxy ..|> ServiceInterface
Service ..|> ServiceInterface
Proxy o--> Service
Singleton
classDiagram
direction LR
class Singleton {
-Singleton instance$
-Singleton()
+getInstance()$ Singleton
}
class Client
Client --> Singleton : use
Singleton --> Singleton : create, has
State
classDiagram
direction BT
class Context {
-state
+Context(initialState)
+changeState(state)
+doThis()
+doThat()
}
class State {
<<interface>>
+doThis()
+doThat()
}
class ConcreteStates {
-context
+setContext(context)
+doThis()
+doThat()
}
class Client
Context o--> State
ConcreteStates ..|> State
ConcreteStates --> Context
Client ..> ConcreteStates
Client --> Context
Strategy
classDiagram
direction BT
class Client
class Context{
-strategy
+setStrategy(strategy)
+doSomething()
}
class Strategy{
<<interface>>
+execute(data)
}
class ConcreteStrategies{
+execute(data)
}
Client --> Context: use
Client ..> ConcreteStrategies: create
Context o--> Strategy
ConcreteStrategies ..|> Strategy
TemplateMethod
classDiagram
direction BT
class AbstractClass{
<<abstract>>
+templateMethod()
+step1()
+step2()
+step3()*
+step4()*
}
class ConcreteClass1{
+step3()
+step4()
}
class ConcreteClass2{
+step1()
+step2()
+step3()
+step4()
}
ConcreteClass1 --|> AbstractClass
ConcreteClass2 --|> AbstractClass
Visitor
classDiagram
direction BT
class Client
class ConcreteVisitors {
+visit(e: ElementA)
+visit(e: ElementB)
}
class Visitor {
<<interface>>
+visit(e: ElementA)
+visit(e: ElementB)
}
class ElementA {
+featureA()
+accept(v: Visitor)
}
class ElementB {
+featureB()
+accept(v: Visitor)
}
class Element {
<<interface>>
+accept(v: Visitor)
}
Client ..> ConcreteVisitors
ConcreteVisitors ..|> Visitor
Element ..> Visitor
ElementA ..|> Element
ElementB ..|> Element
Visitor ..> ElementA
Visitor ..> ElementB
Client ..> Element
参照
refactoring.guru様のクラス図を参考にしております。
以下のUsage policyに従っております。
While most of this website is protected by copyright, we permit free usage of content and illustrations as long as you place a hyperlink to the specific page (or print its URL if it’s printed media) where the content is taken from (or just the home page if multiple pieces of content is used) in the following bounds:
You can cite any text on this website, as long as it’s not a substantial part of the cited article.
You can use up to 10 illustrations from this website in total for all of your publications and presentations.
本サイトの大部分は著作権で保護されていますが、以下の範囲内で、コンテンツを引用した特定のページ(印刷媒体の場合はそのURLを印刷したもの)へのハイパーリンク(複数のコンテンツを使用した場合はトップページのみ)を設置していただければ、コンテンツやイラストの自由利用を許可します。
引用された論文の実質的な部分でない限り、当サイトのどの文章を引用してもかまいません。
本サイトに掲載されている図版は、出版物やプレゼンテーションに使用する場合、合計10点までとします。
Discussion