LoginSignup
1
1

More than 3 years have passed since last update.

GoF javaデザインパターン ざっくり要約

Last updated at Posted at 2020-06-03

この記事は「Java言語で学ぶ デザインパターン入門」を自分用に要約したものになっています

Iterater

目的

配列などの集合体を順に要素にアクセスする。

内容

hasNext()は次の要素があるかbooleanで返す。次に要素があるかチェックし、next()を実行
next()は次の要素のアクセス

Adopter

目的

API間のズレをなくす

メリット

二つのAPIの間に入りズレをなくす部品を作ることで、再利用性が高くなる。
既存のクラスに調整を加えずに、目的のインターフェース(API)を実装すること

Template Method

目的

スーパークラスで処理の枠組みを決め、サブクラスで具体的な処理を記述する。

メリット

ロジックは共通化することができる。

注意

親クラスは抽象クラス(abstract)で定義。interfaceだと親クラスは処理を書くことはできない。

Factory Method

目的

インスタンス生成を親クラスで定義する(具体的なクラス名は定義しない)。子クラスでは肉付けを行う。

Singleton

目的

たった一つだけしか、インスタンス生成をしない
コンストラクタをprivateにすることで、クラス外でインスタンス生成ができないようにする。
インスタンスのアクセス方法は、getInstance()で唯一のインスタンスを返すだけにする。

注意

private static Singleton singleton = null;
if(singleton == null){
    singleton = new Singleton;
}

という条件式だと複数スレッドで実行したときにマシンの状態によって複数インスタンスが作成されてしまうことがある。非同期にするか、事前に作成しておく。

Prototype

目的

コピーしてインスタンスを作る。

注意

cloneメソッドはshallow copy。インスタンスの中身までをコピーするdeep copyはオーバーライドして実装。
shallow copyはインスタンスのフィールドの内容をそのままコピーするだけ。
cloneメソッドは初期化はしないため別で初期化する必要あり

Builder

目的

全体の構造を親クラスで作り、段階を踏んで複雑な処理を積み上げていく
独立性を高めることで、修正箇所や追加箇所をわかりやすくする。

Abstract Factory

目的

抽象的な工場と抽象的な部品を使用する。

注意

具体的な工場を追加するのは簡単。
新たに部品を追加するのは困難(具体的な工場全体に)

Bridge

目的

機能と実装をわけ、橋渡しをする。
機能・・・処理など
実装・・・実装に使用する場合のクラス

機能を増やすと実装クラスには全て機能が追加されるため、機能を増やしやすくなる。

注意

実装が複雑になってしまうことが多いため、実装の部分を頻繁に変える場合のみ使用する。例えば、OS依存に対する対応は、
機能は修正せずに、実装だけ変えることができる。

Facade

目的

インターフェースを単純化する。
複雑な処理を隠蔽する。複雑な処理の窓口役になる。

注意

packageのみだけしかアクセスできないようにするには、

//public
public class Sample{

}

// package内でしかアクセスできないようにする。
class Sample{

}

Strategy

目的

アルゴリズムを変えることができる。
委譲を使うことで継承より弱い結びつきになり、アルゴリズムを簡単に変えることができる。

Composite

目的

木構造にする。
容器と中身を同一視して、再帰的な構造にする。
composite -> 「混合物」「複合物」

FileDirectory

ファイルディレクトリはファイルとディレクトリがある。
ファイルを順に見ていくとき、サブディレクトリかファイルかは同一視して見ていく。
image.png

DirectoryはEntryに再起的にアクセス可能。
Fileは木構造だとすると、葉
Directoryは枝。

  • HTML
  • メニュー表

Decorator

目的

機能の核から、一皮一皮上から被せて、追加していく。
中身を追加せずに、機能を追加することができる。
委譲を使うことで、緩やかな結合をするため、動的な機能追加ができる。
透過的なインターフェース(API)を保ったまま、オブジェクトを被せて機能を追加していく。

デメリット

小さいクラスが増えてしまう。

(番外編)継承と委譲

継承 -サブクラスは、スーパークラスと同一視することができる-

class Parent {
    ...
    void parentMethod(){
        ...
    }
}
class Child extends Parent {
    ...
    void childMethod(){
        ...
    }
}

Parent obj = new Child();
obj.parentMethod();
Childのインスタンスは、Parent型の変数にそのまま代入できる。Parentから継承しているメソッドを呼び出すことができる。
つまり、
ChildのインスタンスをあたかもParentのインスタンスであるかのように扱っている。
これはサブクラスをスーパークラスと見なす例



逆に
スーパークラスをサブクラスだと見なすにはキャストが必要

Parent obj = new Child();
((Child)obj).childMethod();

委譲 -自分と委譲先を同一視

委譲を使ってインターフェースが透過的になっている場合は、自分と委譲先の同一視をすることが可能

class Rose {
    Violet obj = ...
    void method(){
        obj.method();
    }
}

class Violet {
    void method(){
        ...
    }
}

RoseとVioletは同じメソッドを持っていて、RoseはVioletに委譲している...が共通のメソッドと言うのが明記されていない。

abstract class Flower {
    abstract void method();
}

interface Flower {
    abstract void method();
}

上記のように明記することが可能
場合によって使い分ける。

Visitor

目的

データ構造と処理を分ける。データ構造を訪問するvisitorクラスを作って、そのクラスに処理をしてもらう。

image.png

データ構造を保持している要素に特定の処理をする。
Visitorパターンは、 FileクラスやDirectoryクラスの 部品としての独立性を高めていることになる。 もし、 処理の内容をFileクラスや Directoryクラスのメソッドとしてプログラムしてしまうと、 新しい「処理」を追加して機能拡張したくなるたびに、 FileクラスやDirectoryクラスを修正しなければならなくなる。

Chain of Responsibility

目的

責任のたらい回し
要求する側と処理する側の結びつきを弱くする。
次の人が処理できなかったら、次の人に処理してもらう、、、、を繰り返し処理をたらい回しにする。

次の要求先は小クラスが決めない。小クラスが決めると部品の独立性を損なってしまう。
各オブジェクトが仕事に集中できると言う利点がある。

ウィンドウシステムによく使われる。

注意

要求と処理が決まっている場合はchain of responsibilityを使用すると遅くなってしまう場合がある。

Mediator

目的

メンバは相談役に相談し、相談役からのみ指示を受ける。
多数のオブジェクトの調整が必要な時に使える。
個々のオブジェクトが通信するわけではなく、相談役にのみ通信する。

複雑に絡み合う通信を整理して一つの相談役をおきそこに通信する。

State

目的

「状態」をクラスとして表現する。
状態遷移は誰が行うかは注意が必要。
状態遷移はクラスのインスタンスを変更をすることで実現する。
新しい状態を追加するのは簡単

Observer

目的

観察対象の状態が変更されたら検知して、観察者に通知する。
状態が変更された時に処理したい時に使われる。
観察していると言うより、受動的に変更を待っている感じ。

observerパターンは、MVCモデルのModelとViewを、Subject役Observer役に対応している。

Command

目的

複数の処理をまとめて命令(command)にする。

Memento

目的

状態を保存する。
エディタなどのundoを可能にする。
ある時点での状態を保存し、あとでその状態に復元できるようにする。(ゲームのセーブみたいに)
オブジェクトの内容を他に公開せずに状態を保存することができる。

注意

状態を保存する賞味期限はいつまでにするか問題がある。
Mementoオブジェクトを複数用意すると複数の地点で復元できる。
狭いインターフェース(API)でしかアクセスできないようにする。そうしないと

その他

アクセス修飾子

スクリーンショット 2020-06-01 18.32.36.png

LSP(リスコフの置換原則)

親クラスが関係式に対し真であれば、親クラスの派生した小クラスも真である。(置換可能性)

The Open-Closed Principle

特別な理由がない限り将来の拡張を禁止してはいけない。
しかし、拡張を行うたびに既存のクラスが修正しなくてはならないのはだめ。

つまり、既存のクラスを修正せずに拡張できるようにせよ
ということ。

再利用性の高いクラスは閉じられている。
Stringは再利用性が高い、また拡張すると効率が悪くなってしまうため、閉じられている。(finalクラスで定義されているため拡張できない)

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1