GitEngHar / WorkUp

LearnJava
0 stars 0 forks source link

デザインパターンを理解したい #7

Closed GitEngHar closed 6 months ago

GitEngHar commented 6 months ago

https://github.com/GitEngHar/learnJava/issues/1 上記に紐づく Issue

GitEngHar commented 6 months ago

## テンプレ用
### aaa

#### コード

◆aaa
```java

実行結果

GitEngHar commented 6 months ago

デザインパターン

学ぶ意義

コードは千差万別だが細かく見ると似通っている点が多く、またクラスのユースケースにおいても大体ケースは同一である
大体のケースに対してのベストプラクティスな構造が存在する
中でも Gof と呼ばれるものがあり、これは多くのパターンが存在するが大まかに以下の3種類に分類できる

学ぶメリット
GitEngHar commented 6 months ago

生成パターン

AbstractFactory

※わからないので一旦Pass
関連するインスタンス群をまとめて宣言する

Builder

構成が同様のものにおいて、その過程を隠蔽し同じ過程で異なる内部インスタンスを得る
複雑な処理を記述している クラスA (目的を果たす処理の区分は一緒) 処理の流れを記述している クラスB

クラスBをBuild用クラスとしておけば、実装者は決まった処理の流れで該当部分の記述に専念できる

https://github.com/GitEngHar/learnJava/tree/main/JavaNative/Books/honkaku/DesignPatern/src

Singleton (直訳 : トランプの一枚札)

常に同一のインスタンスを使いまわすときに利用する
複数のスレッドがインスタンスに同時にアクセスしても問題がないように検証する必要がある

【例 : 設定情報を使いまわす処理】

◆表現方法

public Configure {
  private static Configure instance = new Configure();
  private configure(){
  // 設定情報を読み込む処理
  }
  public static Configure getinstance(){
   return instance;
  }
}
GitEngHar commented 6 months ago

構造パターン

Adapter

継承

インターフェースに互換性のないクラス同士を組み合わせる

インターフェースと既存のシステムを継承し、少し書き換えて実行

※このやり方では abstruct を用いて実装することはできない (新システム用Interfaceがabstruct となり 2つ継承する必要があるため)

委譲

abstruct を Adapterの対象としたい場合 委譲

既存のクラスを変更することなく利用するパターン
継承以外の方法で内部の処理を呼び出したいときに利用すべし

Composite

再帰的な構造で用いる(ファイル/ディレクトリ構造)
処理を記述する側はファイル/ディレクトリの差を意識することなく操作で来ていた方がいい という要望を叶える構造

ファイル と ディレクトリの差を意識せず処理を行う
インターフェースを共通のものを利用することで、可能となっている
そのため、オブジェクトに対しての処理を共通化することができる(例 : FileとDirを削除する処理を1ループ内でまとめて実行できる )

GitEngHar commented 6 months ago

振る舞いパターン

Command

「命令」をインスタントして扱う。処理の組み合わせが簡単になる
挙動が利用するクラスによって変化する場合、抽象クラスを作成し、各挙動に応じた動作を定義しておくといい

Strategy

戦略を簡単に切り替えられる仕組み
条件に応じて処理アルゴリズムを変更する仕組み

Strategyとコマンドの違いは実行単位でみるとわかりやすい


public static void strategyBooks(){ # Strategy
        strategy.Book comic = new strategy.Book(600);
        strategy.Book technicalBook = new strategy.Book(2000);

        strategy.Strategy discount = new DiscountStrategy();
        strategy.Strategy specialDiscount = new specialDiscount();

        strategy.Shop discountShop = new Shop(discount);
        strategy.Shop specialShop = new Shop(specialDiscount);

        discountShop.sell(comic);
        specialShop.sell(technicalBook);

        System.out.printf("漫画の値段 : %f",comic.getAmount());
        System.out.printf("漫画の値段 : %f",technicalBook.getAmount());

    }
    public static void commandBooks(){ # Command
        command.Book comic = new command.Book(600);
        command.Book technicalBook = new command.Book(1700);

        Command discountCommand = new Discount();

        Command specialdiscoutCommand = new SpecialDiscount();

        discountCommand.setBook(comic);
        discountCommand.execute();
        System.out.printf("割引した漫画の値段は %f 円です%n",comic.getAmount());

        specialdiscoutCommand.setBook(technicalBook);
        specialdiscoutCommand.execute();
        System.out.printf("割引した技術書の値段は %f 円です",technicalBook.getAmount());
    }
違い説明

Commandは命令単位でインスタンス化するため、 特別割引 割引 という処理をインスタンスのメソッドを実行することで目的を果たしている

Strategyはロジック単位でインスタンス化する為、インスタンス化したロジックを処理を実施するクラスに渡すことで目的を果たしている

Iterator

for-each 処理の中身はIterator が実行されている
Iterator の 意味は 繰り返しをおこなうもの

配列の中身を走査する仕組みとなっており、HashMapもListもこれを元にされているため違いを意識することなく利用出来る

Observer

インスタンスの状態変化を通知する

アクションをきっかけに状態の変化するインスタンス、ボタンの押下 や システムからのデータ受信等 がこれにあたる
単純に上記を実装をすると、呼び出す処理と実際の処理の関係が密になってしまい、拡張性が悲しいことになる
呼び出すきっかけを増やしたり減らしたり、呼び出し処理を変更したい場合に大きな手間がかかる

Observer は 観測者 を意味する
インスタンス自信が自分の状態の変化を検知する仕組み

このパターンは実際に関連を持たないインスタンスの状態変化を通知することができるため、 状態が変化した際にアクションを実施したい場合はこれを利用する

GitEngHar commented 6 months ago

これらを用いることができれば、無駄のない品質の高いコードを書くことができるので意識する!!ぞー!