JAVAの23種類のデザインパターンを解説

JAVAの23のデザインパターンを以下に説明します。

 

 

1. シングルトン パターンの定義
: クラスのインスタンスが 1 つだけであることを確認し、そのインスタンスへのグローバル アクセス ポイントを提供します。
汎用コード: (スレッド セーフです)

public class Singleton {
 private static final Singleton singleton = new Singleton();
//限制产生多个对象
 private Singleton(){
 }
 //通过该方法获得实例对象
 public static Singleton getSingleton(){
 return singleton;
 } 
 //类中其他方法,尽量是 static
 public static void doSomething(){
 } }

使用シナリオ:
● 一意のシリアル番号の生成が必要な環境
● Web ページ上のカウンターなど、プロジェクト全体で共有アクセス ポイントまたは共有データが必要なため、更新のたびに記録する必要がないデータベースに格納し、シングルトン モードを使用する カウンタの値を保持し、スレッド セーフを確保する
● IO やデータベースなどのリソースへのアクセスなど、リソースを大量に消費するオブジェクトを作成する
● 多数の静的定数を定義する必要がある環境内の静的メソッド(ツールクラスなど)では、シングルトンモードを採用できます(もちろん、直接静的として宣言することもできます)。

スレッドの安全でない例:

public class Singleton {
 private static Singleton singleton = null;
 //限制产生多个对象
 private Singleton(){
 } 
 //通过该方法获得实例对象
 public static Singleton getSingleton(){
 if(singleton == null){
 singleton = new Singleton();
 }
 return singleton;
 } }

解決策:
getSingleton メソッドの前に synchronized キーワードを追加するか、getSingleton メソッドに synchronized を追加して実現します。最適なアプローチは、汎用コードとして記述することです。

2. ファクトリ モード
定義: オブジェクトを作成するためのインターフェイスを定義しますが、どのクラスをインスタンス化するかはサブクラスに決定させます。ファクトリ メソッドでは、クラスのインスタンス化をサブクラスに延期させます。
クラス。ファクトリ メソッドは、クラスのサブクラスへのインスタンス化を遅らせます。)
Product は抽象プロダクト クラスのプロダクトの共通性を定義し、最も抽象的な物事の定義を実現します。Creator は
抽象化のためのクラス、つまり抽象ファクトリを作成します。プロダクト クラスの作成は、具体的な実装ファクトリ ConcreteCreator によって行われます。
特定のファクトリ クラス コード:

public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
 Product product=null;
 try {
 product =
(Product)Class.forName(c.getName()).newInstance();
 } catch (Exception e) {
 //异常处理
 }
 return (T)product; 
 } }

シンプル ファクトリ モード:
モジュールにはファクトリ クラスが 1 つだけ必要で、生成する必要はなく、静的メソッドを使用します。 複数のファクトリ クラス:
各種族 (特定の製品クラス) が作成者に対応し、各作成者は独立して責任を負います。 対応する製品オブジェクトを作成します。これは、シングルトン パターンではなく単一責任の原則と非常に一致しています。シングルトン パターンの中心的な要件は、メモリ内にオブジェクトが 1 つだけ存在し、ファクトリ メソッド モードの遅延初期化
を通じてメモリ内に生成できるオブジェクトは 1 つだけであることです。ProductFactory は、製品クラスのオブジェクト作成作業を担当し、prMap 変数を通じてキャッシュを生成します。このキャッシュは、再度再利用する必要があるオブジェクト用に予約されています。 使用シナリオ: jdbc がデータベースに接続し、ハードウェアにアクセスし、オブジェクトの生成と破棄を削減します


3. 抽象ファクトリ パターン
定義: 具体的なクラスを指定せずに、関連または依存するオブジェクトのファミリーを作成するためのインターフェイスを提供します
(特定の種類を指定せずに、関連または相互依存するオブジェクトのグループを作成するためのインターフェイスを提供します)。

抽象ファクトリークラスコード:


public abstract class AbstractCreator {
 //创建 A 产品家族
 public abstract AbstractProductA createProductA();
 //创建 B 产品家族
 public abstract AbstractProductB createProductB();
}

使用シナリオ:
オブジェクトのファミリー (または関係のないオブジェクトのグループ) にはすべて同じ制約があります。
さまざまなオペレーティング システムに関しては、抽象ファクトリ パターンの使用を検討できます。

4. テンプレート メソッド パターン定義
: 操作内のアルゴリズムのスケルトンを定義し、一部のステップをサブクラスに延期します。テンプレート メソッドを使用すると、アルゴリズムの
構造を変更せずにサブクラスでアルゴリズムの特定のステップを再定義できます。アルゴリズムのフレームワークと一部のステップは遅延されます。 AbstractClass は
抽象テンプレート
と呼ばれ、そのメソッドは次の 2 つのカテゴリに分類されます。
● 基本メソッド
基本メソッド (基本とも呼ばれます)操作は、サブクラスによって実装され、テンプレート メソッドで呼び出されるメソッドです。
● テンプレートメソッド メソッド
は 1 つまたは複数存在しますが、一般的には、基本メソッドのスケジューリングを実装し、固定ロジックを完成させる特定のメソッド、つまりフレームワークです。
注: 悪意のある操作を防ぐために、一般的なテンプレート メソッドは Final キーワードを使用して追加されており、上書きすることはできません。
具象テンプレート: ConcreteClass1 および ConcreteClass2 は具象テンプレートに属し、親クラスによって定義された 1 つ以上の抽象メソッドを実装します。つまり、親クラスによって定義された基本メソッドはサブクラスに実装できます。 シナリオ: ● 複数のサブクラスにパブリック メソッドがある

ロジックが基本的に同じである場合。
● 重要で複雑なアルゴリズムについては、コアアルゴリズムをテンプレートメソッドとして設計し、その周囲の関連する詳細な機能を各サブクラスで実現できます。
● リファクタリングの際、テンプレートメソッドパターンは頻繁に使用されるパターンで、同じコードを親クラスに抽出し、フック関数を通じてその動作を制約します (「テンプレートメソッドパターンの拡張」を参照)。

5. ビルダー パターンの定義
: 複雑なオブジェクトの構築をその表現から分離し、同じ構築プロセスで異なる表現を作成できるようにします (同じ構築プロセスで異なる表現を作成できるように、複雑なオブジェクトの構築をその表現から分離します) )
● Product プロダクト クラスは
、通常、テンプレート メソッド パターンを実装します。つまり、テンプレート メソッドと基本メソッドがあり、例では BenzModel と BMWModel がプロダクト クラスに属します。
● ビルダー 抽象ビルダー
標準化された製品の構築は、通常、サブクラスによって実現されます。例の CarBuilder は抽象ビルダーに属します。
● ConcreteBuilder は、
抽象クラスによって定義されたすべてのメソッドを実装し、構築されたオブジェクトを返します。例の BenzBuilder と BMWBuilder はコンクリート建設業者に属します。
● ディレクター ディレクタークラスは
、既存のモジュールの順序を調整し、ビルダーに構築の開始を指示します
使用シナリオ:
● 同じメソッド、異なる実行順序、異なるイベント結果が生成される場合、ビルダー モードを使用できます。 。
● 複数のコンポーネントまたは部品を 1 つのオブジェクトに組み立てることができますが、生成される実行結果が異なる場合は、このモードを使用できます。
● 製品クラスが非常に複雑であるか、製品クラスの呼び出しシーケンスによってさまざまな効果が生じるため、現時点ではビルダー パターンを使用することが非常に適切です。
ビルダー パターンとファクトリー パターンの違いは次のとおりです。
ビルダー パターンの主な機能は、基本メソッドの呼び出し順序の整理です。これらの基本メソッドは実装されており、
異なる順序で生成されるオブジェクトも異なります。
ファクトリ メソッドは作成に焦点を当て、パーツの作成が主です。組立順序は自己責任ではございません。

6. プロキシ パターンの定義: 別のオブジェクトへの
アクセスを制御するためのサロゲートまたはプレースホルダを提供します
抽象クラスまたはインターフェイスにすることができます。特別な要件を必要としない最も一般的なビジネス タイプの定義です。● RealSubject 具体的な主体の役割委任された役割、委任された役割とも呼ばれます。それは利用される側であり、ビジネス ロジックの具体的な実行者です。● プロキシ プロキシテーマロールデリゲートクラス、プロキシクラスとも呼ばれます。これは実際のロールの適用を担当し、抽象テーマ クラスによって定義されたすべてのメソッド制限の実装を実際のテーマ ロールに委託し、実際のテーマ ロールが処理される前後に前処理と後処理作業を実行します。通常のプロキシと必須プロキシ:通常のプロキシは、アクセスする前にプロキシの存在、つまり同様の GamePlayerProxy クラスの存在を知る必要があることを意味します; 必須プロキシは、呼び出し元が気にせずに実際のキャラクターを直接呼び出すことを意味しますプロキシが存在するかどうか、そのプロキシの世代は実際の文字によって決まります。通常のプロキシ:このモードでは、呼び出し元はプロキシのみを知っており、実際の役割が誰であるかを知る必要はありません。これにより、高レベルのモジュールに対する実際の役割の変更の影響が保護され、実際のテーマの役割を変更できます。インターフェイスに対応したメソッドを実装する限り影響はなく、高い拡張性が必要な場合に最適なモードです。強制プロキシ:













プロキシを強制する概念は、実際の役割からプロキシの役割を検索することであり、実際の役割への直接アクセスは許可しません。上位モジュールは getProxy を呼び出す限り、実ロールのすべてのメソッドにアクセスでき、プロキシを生成する必要はまったくなく、プロキシの管理は実ロール自体で完了します。
動的プロキシ:
プロキシされるインターフェイスに従ってすべてのメソッドを生成します。つまり、インターフェイスが与えられると、動的プロキシは「このインターフェイスの下にすべてのメソッドを実装しました」と宣言します。
2つの独立した開発ライン。動的プロキシはプロキシの責任を実現し、ビジネス ロジック サブジェクトは関連するロジック機能を実現します。両者の間には必要な相互結合関係はありません。別の側面から介入するようにアドバイスを通知し、
最終的に高レベルのモジュール、つまりクライアントに結合して、ロジックのカプセル化タスクを完了します。
動的プロキシ呼び出しプロセスの概略図:
動的プロキシの目的: 既存のコードの構造を変更せずにオブジェクトの動作を強化または制御するためのクロスセクション プログラミング。
最初の条件: プロキシされたクラスはインターフェイスを実装する必要があります。

7. プロトタイプ パターン
定義: プロトタイプ インスタンスを使用して作成するオブジェクトの種類を指定し、このプロトタイプをコピーして新しいオブジェクトを作成します
。)
プロトタイプ モードの一般的なコード:


public class PrototypeClass implements Cloneable{
 //覆写父类 Object 方法
 @Override
 public PrototypeClass clone(){
 PrototypeClass prototypeClass = null;
 try {
 prototypeClass = (PrototypeClass)super.clone();
 } catch (CloneNotSupportedException e) {
 //异常处理
 }
 return prototypeClass;
 } }

プロトタイプ モードでは、実際には Cloneable インターフェイスを実装し、 clone() メソッドを書き換えます。
プロトタイプ モードを使用する利点:
● 優れたパフォーマンス
プロトタイプ モードはメモリ バイナリ ストリームのコピーであり、特にループ本体で多数のオブジェクトを生成する場合、プロトタイプでは、オブジェクトを直接新規作成するよりもはるかに優れています。モードはその利点をよりよく反映できます。
● コンストラクタの制約の回避
これは長所でもあり短所でもありますが、メモリに直接コピーすると、コンストラクタは実行されません (13.4 節を参照)。
使用シナリオ:
● リソース最適化シナリオ
クラスの初期化では、データやハードウェア リソースを含む大量のリソースを消費する必要があります。
● パフォーマンスおよびセキュリティ要件のあるシナリオ
new によるオブジェクトの作成には非常に面倒なデータの準備またはアクセス権が必要なため、プロトタイプ モードを使用できます。
● 1 つのオブジェクトに複数の修飾子があるシナリオ
オブジェクトが他のオブジェクトからアクセスされる必要があり、各呼び出し元がその値を変更する必要がある場合は、プロトタイプ モードを使用して、呼び出し元が使用できるように複数のオブジェクトをコピーすることを検討できます。
浅いコピーと深いコピー:
浅いコピー: Object クラスによって提供されるメソッド clone はオブジェクトをコピーするだけであり、オブジェクト内の配列および参照オブジェクトはコピーされませんが、元のオブジェクトの内部要素アドレスを指し続けます。コピーのコピーは浅いコピーと呼ばれ、int、long、char、string (プリミティブ型として) などの他のプリミティブ型もコピーされます。
注: プロトタイプ モードを使用する場合、参照されるメンバー変数はコピーされる前に 2 つの条件を満たす必要があります: 1 つはメソッド内の変数ではなくクラスのメンバー変数であること、もう 1 つは変更可能な参照オブジェクトであること、プリミティブ型または不変オブジェクトではありません。
ディープ コピー: プライベート クラス変数の独立したコピーを作成します。
例:thing.arrayList = (ArrayList)this.arrayList.clone();

8. メディエーター モード
定義: オブジェクトのセットがどのように相互作用するかをカプセル化するオブジェクトを定義します。メディエーターは、オブジェクトが相互に明示的に参照しないようにすることで疎結合を促進し、相互
作用を個別に変更できるようにします。(一連のオブジェクトをカプセル化するにはメディエーター オブジェクトを使用します)オブジェクト相互作用の場合、メディエータはオブジェクトが明示的に相互作用する必要をなくすため、結合が緩やかになり、オブジェクト間の相互作用を独立して変更できます。) ● メディエータ抽象メディエータ ロール 抽象メディエータ ロールは、統一されたインターフェイスを定義し
ます
。 、同僚間のコミュニケーションの役割を使用します。
● 具体的調停者 具体的調停者の役割は、
さまざまな同僚の役割を調整することで協調行動を実現するため、各同僚の役割に依存する必要があります。
● 同僚の役割
すべての同僚は仲介者の役割を知っており、他の同僚とコミュニケーションをとるときは、仲介者の役割を通じて協力する必要があります。各同僚クラスの動作は 2 つのタイプに分けられます: 1 つは、オブジェクト自体の状態の変更、独自の動作の処理など、同僚自体の動作です。依存関係はありません。2 つ目は、必要な動作です。依存メソッド (Dep-Method) と呼ばれる、仲介者に依存して完了します。
一般的な抽象メディエーター コード:

public abstract class Mediator {
 //定义同事类
 protected ConcreteColleague1 c1;
 protected ConcreteColleague2 c2;
 //通过 getter/setter 方法把同事类注入进来
 public ConcreteColleague1 getC1() {
 return c1;
 }
 public void setC1(ConcreteColleague1 c1) {
 this.c1 = c1;
 }
 public ConcreteColleague2 getC2() {
 return c2;
}
 public void setC2(ConcreteColleague2 c2) {
 this.c2 = c2;
 }
 //中介者模式的业务逻辑
 public abstract void doSomething1();
 public abstract void doSomething2();
}

ps: 抽象インジェクションの代わりに同僚クラス インジェクションを使用する理由は、抽象クラスには、すべての同僚クラスが完了する必要があるメソッドがないためです。つまり、同僚クラスごとにメソッドが異なります。
質問: なぜ同僚クラスはコンストラクターを使用してメディエーターを注入し、メディエーターはゲッター/セッター メソッドを使用して同僚クラスを注入する必要があるのですか?
これは、同僚クラスにはメディエーターが必要ですが、メディエーターは同僚クラスの一部しか持つことができないためです。
使用シナリオ:
中間パターンは、複数のオブジェクト間の密結合に適しています。密結合の標準は、クラス図にクモの巣構造が現れる、つまり、各クラスが他のクラスと直接の関係を持つことです。

9. コマンド モード
定義: リクエストをオブジェクトとしてカプセル化することで、さまざまな
リクエスト、キューまたはログ リクエストでクライアントをパラメータ化できるようになり、取り消し可能な操作をサポートします。● Receive Receiver ロールこのロールはワークのロールであり、ここ、具体的には上記に渡されたときにコマンドが実行される必要があります。 この例では、Group の 3 つの実装クラス (要件グループ、アート グループ、コード グループ) があります。 。● コマンドの役割実行するすべてのコマンドをここで宣言します。● Invoker Invoker ロールコマンドを受信して​​実行します。この例では、私 (プロジェクト マネージャー) がこの役割を担っています。使用シナリオ:コマンドモードは、コマンドとみなされる場合に使用できます。たとえば、GUI 開発では、ボタンのクリックがコマンドとなり、コマンドモードが使用できます。もちろん、DOS コマンドをシミュレートする場合にも、コマンドモードが使用できます。コマンド モードも使用する必要があります (トリガー フィードバック メカニズムの処理など)。








10. 責任チェーン モード
の定義: 複数のオブジェクトにリクエストを処理する機会を与えることで、リクエストの送信者とその受信者の結合を回避します。受信オブジェクトをチェーンし、オブジェクトが処理するまでそのチェーンに沿ってリクエストを渡します。オブジェクトには
、これにより、リクエストの送信者と受信者の結合関係が回避されます。これらのオブジェクトをチェーンに接続し、
オブジェクトが処理するまでこのチェーンに沿ってリクエストを渡します。)
抽象化ハンドラーのコード:


public abstract class Handler {
 private Handler nextHandler;
 //每个处理者都必须对请求做出处理
 public final Response handleMessage(Request request){
 Response response = null; 
 //判断是否是自己的处理级别

if(this.getHandlerLevel().equals(request.getRequestLevel())){
 response = this.echo(request);
 }else{ //不属于自己的处理级别
 //判断是否有下一个处理者
 if(this.nextHandler != null){
 response =
this.nextHandler.handleMessage(request);
 }else{
 //没有适当的处理者,业务自行处理
 }
 }
 return response;
 }
 //设置下一个处理者是谁
 public void setNext(Handler _handler){
 this.nextHandler = _handler;
 }
 //每个处理者都有一个处理级别
 protected abstract Level getHandlerLevel();
 //每个处理者都必须实现处理任务
 protected abstract Response echo(Request request);
}

抽象プロセッサは 3 つの役割を実装します:
1 つは、外部に公開される唯一のメソッドであるリクエスト処理メソッド handleMessage を定義することです; もう 1 つは、次のプロセッサ
を設定するためのチェーン配置メソッド setNext を定義することです
; 実装には 2 つの方法があります:
特定の処理タスクを処理およびエコーできるレベル getHandlerLevel 。
注:
チェーンが超長くなる事態を避けるためにチェーンのノード数を制御する必要があるが、Handler で最大ノード数を設定し、setNext メソッドでそのしきい値を超えたかどうかを判定する方法が一般的である。それを超えると、システムのパフォーマンスが意図せず中断されることを避けるために、チェーンの確立が許可されません。

11. デコレータ パターン
定義: 同じインターフェイスを動的に維持しながら、オブジェクトに追加の責任を追加します。デコレータは、
機能を拡張するためのサブクラス化に代わる柔軟な手段を提供します (オブジェクトにいくつかの追加の責任を動的に追加します。機能の追加という点では、装飾モードはより詳細です)サブクラスを生成するよりも柔軟です。)
● コンポーネント抽象コンポーネント
コンポーネントは、コア オブジェクト、つまり上記のトランスクリプトなどの最も基本的なオブジェクトを定義するインターフェイスまたは抽象クラスです。
注: デコレーション モードでは、
コンポーネントの抽象コンポーネントとして、最も基本的でコアな独自のインターフェイスまたは抽象クラスが存在する必要があります。
● ConcreteComponent 具体コンポーネント
ConcreteComponent は、インターフェイスまたは抽象クラスのコアであり、最も独創的で、最も基本的な実装であり、装飾するものです。
● Decorator Decorator は
一般に抽象クラスですが、何に使用されますか? インターフェイスまたは抽象メソッドを実装するには、その中に必ずしも抽象メソッドが存在する必要はなく、そのプロパティに Component 抽象コンポーネントを指すプライベート変数が存在する必要があります。
● 特定の装飾ロール
ConcreteDecoratorA と ConcreteDecoratorB は 2 つの特定の装飾クラスです。コアとなる、最も原始的で基本的なものを他のものに装飾する必要があります。上記の例は、平凡な通知表を親として認識された成績証明書として装飾することです

使用シナリオ:
● クラスの機能を拡張するか、クラスに追加の機能を追加する必要がある。
● オブジェクトに動的に機能を追加する必要があり、これらの機能は動的に取り消すことができます。
● 兄弟のバッチに対して機能を変更または追加する必要があります。もちろん、これは装飾モードの最初の選択です。

12. 戦略パターン
定義: アルゴリズムのファミリーを定義し、各アルゴリズムをカプセル化し、それらを
交換可能にする (アルゴリズムのセットを定義し、各アルゴリズムをカプセル化し、それらを交換可能にする)
● コンテキストカプセル化ロール
コンテキストロールとも呼ばれます。前後のカプセル化の間のリンクとして機能し、高レベルのモジュールをポリシーやアルゴリズムへの直接アクセスから保護し、可能性のある変更をカプセル化します。
● 戦略の抽象化戦略の役割
戦略とアルゴリズム ファミリの抽象化 (通常はインターフェイス) は、各戦略またはアルゴリズムが持つ必要があるメソッドと属性を定義します。クラス図の AlgorithmInterface の意味は何ですか、と読者は疑問に思うかもしれませんが、
algorithm は「アルゴリズム」を意味し、組み合わせると意味がわかります。
● ConcreteStrategy 具体的な戦略ロール (複数) は
抽象戦略の操作を実装し、このクラスには特定のアルゴリズムが含まれます。
使用シナリオ:
● 複数のクラスのアルゴリズムや動作がわずかに異なるシナリオ。
●アルゴリズムを自由に切り替える必要があるシーン。
● アルゴリズム ルールを保護する必要があるシナリオ。
注: 特定の戦略の数が 4 を超える場合は、混合モードの使用を検討する必要があります。
戦略モード拡張: 戦略列挙


public enum Calculator {
 //加法运算
 ADD("+"){
 public int exec(int a,int b){
 return a+b;
 }
 },
 //减法运算
 SUB("-"){
 public int exec(int a,int b){
 return a - b;
 }
 };
 String value = "";
 //定义成员值类型
 private Calculator(String _value){
 this.value = _value;
 }
 //获得枚举成员的值
 public String getValue(){
 return this.value;
 }
 //声明一个抽象函数
 public abstract int exec(int a,int b);
}

定義:
● 列挙型です。
●戦略パターンを凝縮して列挙しています。
注:
各列挙項目は列挙型によって制限され、public、final、static となり、スケーラビリティにも一定の制約があるため、システム開発においては、戦略列挙は一般に頻繁に変更されない役割を果たします。
致命的な欠陥: すべての戦略を公開する必要があり、どの戦略を使用するかを決定するのはクライアント次第です。

13. アダプター パターン
定義: クラスのインターフェイスをクライアントが期待する別のインターフェイスに変換します。アダプターを使用すると、互換性のないインターフェイスのために連携できなかったクラスが連携できるようになります。(クラス
のインターフェイスをクライアントが期待するものに変換します。別のインターフェイスで 2 つのインターフェイスを有効にします)クラス アダプタ
:
● ターゲット ターゲット ロール
このロールは、他のクラスがどのインターフェイスに変換されるかを定義します。これが、期待されるインターフェイスです。この例では、IUserInfo インターフェイスがターゲットです。役割。
● Adapte ソース ロール
誰をターゲット ロールに変換しますか。この「誰」がソース ロールです。これは正常に動作する既存のクラスまたはオブジェクトであり、アダプター ロールによってパッケージ化された後は、まったく新しいものになります。そして美しい役柄。
● アダプター ロール
アダプター パターンの中核となるロールです。他の 2 つのロールは既存のロールであり、アダプター ロールは新しく作成する必要があります。その役割は非常に単純です。ソース ロールをターゲット ロールに変換する方法です。継承または
クラス関連付けを通じて。
使用シナリオ:
すでに運用されているインターフェイスを変更したい場合は、アダプター パターンが最適なパターンになる可能性があります。例えば、システムを拡張する場合、既存または新規に作成したクラスを使用する必要があるが、このクラスがシステムのインターフェースに準拠していない場合はどうすればよいでしょうか。この例でも説明されているアダプター パターンを使用します。
注:
詳細設計段階ではアダプタ モードの使用を考慮せず、拡張アプリケーションにはメイン シナリオを使用してください。
オブジェクトアダプター:
オブジェクトアダプタとクラスアダプタの違い:
クラスアダプタはクラス間の継承であるのに対し、オブジェクトアダプタはオブジェクトの複合関係であり、クラスの関連関係とも言えます。二。(実際のプロジェクトではオブジェクトアダプタが使用するシーンが比較的多くあります)。

14. イテレータ パターン
定義: 基礎となる表現を公開せずに、集合オブジェクトの要素に順次アクセスする方法を提供します (
オブジェクト
。抽象反復子
抽象反復子は、要素にアクセスして横断するためのインターフェイスを定義する役割を担っており、基本的に 3 つの固定メソッドがあります:
最初の要素を取得する first() 、次の要素にアクセスする next() 、 isDone() が最後にアクセスしたかどうか
(Java は hasNext() メソッドと呼ばれます)。
● ConcreteIterator 具象イテレータ 具象
イテレータの役割は、コンテナ要素の走査を完了するためにイテレータ インターフェイスを実装する必要があります。
● 集約抽象コンテナ コンテナ
ロールは、特定のイテレータ ロールを作成するためのインターフェイスを提供する責任を負い、
createIterator() のようなメソッド (通常は Java の iterator() メソッド) を提供する必要があります。
● 具象集合体 具象コンテナ 具象
コンテナは、コンテナインタフェースで定義されたメソッドを実装し、イテレータを保持するオブジェクトを作成します。
ps: イテレータ モードが廃止され、Java のさまざまなコレクション クラス (コレクション) にイテレータが適用されるようになりました。Java に付属のイテレータを使用することで、すでにニーズを満たしています。

15. 複合パターン (複合パターン)
の定義: オブジェクトをツリー構造に構成して部分全体の階層を表現します。複合を使用すると、クライアントは個々のオブジェクトと
オブジェクトの構成を均一に扱うことができます。これにより、ユーザーは単一のオブジェクトとオブジェクトの使用に一貫性を保つことができます。 )
● コンポーネント抽象コンポーネント ロールは
、複合オブジェクトの共通メソッドと属性を定義し、この例の getInfo などのいくつかのデフォルトの動作または属性を定義できます。これは抽象クラスにカプセル化されます。
● Leaf リーフコンポーネント
Leaf オブジェクト。その下に他の枝はなく、走査の最小単位です。
● 複合ブランチコンポーネント
ブランチオブジェクト。その機能はブランチノードとリーフノードを組み合わせてツリー構造を形成することです。
ブランチ コンポーネントの一般的なコード:
public class Composite extends Component { //コンポーネント コンテナprivate ArrayList contentArrayList = new ArrayList(); //リーフ コンポーネントまたはブランチ コンポーネントを追加public void add(Componentコンポーネント){ this.componentArrayList.add(コンポーネント) ;






}
//リーフコンポーネントまたはブランチコンポーネントを削除
public void Remove(ComponentComponent){ this.componentArrayList.remove(component); } //ブランチ配下のすべてのリーフコンポーネントおよびブランチコンポーネントを取得public ArrayList getChildren(){ return this.componentArrayList ; } }使用シナリオ: ● ツリー メニュー、ファイルおよびフォルダの管理など、部分と全体の関係シナリオを維持および表示します。● 一部のモジュールまたは機能が全体から分離されるシナリオ。注:ツリー構造である限り、複合モードの使用を検討してください。










16. オブザーバー パターンの定義
: オブジェクト間の 1 対多の依存関係を定義して、1 つのオブジェクトの状態が変化すると、そのすべての依存関係が自動的に通知され、更新されるようにします (オブジェクト間の 1 対多の依存関係を定義して、オブジェクトが変更されるたびに
、状態が変化すると、それに依存するすべてのオブジェクトが通知され、自動的に更新されます。)
● サブジェクト オブザーバー
オブザーバーが実装する必要がある責任を定義し、オブザーバーを動的に追加およびキャンセルできる必要があります。これは通常、抽象クラスまたは実装クラスであり、オブザーバーの管理とオブザーバーへの通知という、オブザーバーとして実現する必要がある義務のみを完了します

● オブザーバー オブザーバー
はメッセージを受信すると、受信した情報を処理する更新 (更新メソッド) 操作を実行します。
● ConcreteSubject 特定のオブザーバーは、
監視対象オブジェクトのビジネス ロジックを定義し、どのイベントが通知されるかを定義します。
● ConcreteObserver 特定のオブザーバー
メッセージ受信後の各オブザーバーの反応は異なり、各オブザーバーは独自の処理ロジックを持ちます。
オブザーバーの一般コード:


public abstract class Subject {
 //定义一个观察者数组
 private Vector<Observer> obsVector = new Vector<Observer>();
 //增加一个观察者
 public void addObserver(Observer o){
 this.obsVector.add(o);
 }
 //删除一个观察者
 public void delObserver(Observer o){
 this.obsVector.remove(o);
 }
 //通知所有观察者
 public void notifyObservers(){
 for(Observer o:this.obsVector){
 o.update();
}
 } }

使用シナリオ:
● 関連する動作シナリオ。アソシエーション動作は分割可能な関係であり、「構成された」関係ではないことに注意することが重要です。
● イベントマルチレベルトリガーシナリオ。
● メッセージキューの処理メカニズムなど、システム間メッセージ交換シナリオ。
注:
● ブロードキャスト チェーンの問題 オブザーバー
パターンでは、最大 1 つのオブジェクトがオブザーバーと監視対象の両方になります。つまり、メッセージは最大 1 回転送されます (2 回渡されます)。
● 非同期処理の問題
オブザーバーが多く、処理時間が比較的長いため、スレッドセーフやキューの問題を考慮して非同期処理を採用しています。

17. ファサード パターン
定義: サブシステム内の一連のインターフェイスに統一インターフェイスを提供します。ファサードは、サブシステムを使いやすくする上位レベルのインターフェイスを定義します (
サブシステムファサード モードは高レベルのインターフェイスを提供し、サブシステムを使いやすくします。)
● ファサード ロール
クライアントは、このロールのメソッドを呼び出すことができます。この役割は、サブシステムのすべての機能と責任を認識しています。通常の状況では、このロールはクライアントから送信されたすべてのリクエストを対応するサブシステムに委任します。つまり、このロールには実際のビジネス ロジックはなく、単なる委任クラスです。
● subsystem サブシステムの役割
同時に 1 つ以上のサブシステムが存在できます。各サブシステムは単一のクラスではなく、クラスのコレクションです。サブシステムはファサードの存在を認識しません。サブシステムにとって、ファサードは単なる別のクライアントです。
使用シナリオ:
● 複雑なモジュールまたはサブシステムに外部アクセス用のインターフェイスを提供する
● サブシステムは比較的独立している - サブシステムへの外部アクセスはブラック ボックス内でのみ操作する必要がある
● 低レベルの担当者によってもたらされるリスクの拡散を防ぐ
注:
● サブシステムは複数のファサードを持つことができます。
ファサードはサブシステム内のビジネス ロジックには関与しません。

18. Memento パターン
定義: カプセル化に違反することなく、オブジェクトの内部状態をキャプチャして外部化し、オブジェクトを後でこの状態に復元できるようにします。
そして、この状態をオブジェクトの外に保存します。このようにして、オブジェクトを元の保存状態に復元できます。 ) ●
Originator ロールは
、現時点での内部状態を記録し、どの状態がバックアップ範囲に属するかを定義し、メモ
データの作成と復元を担当します。
● Memento ロール (単純な Javabean) は、
Originator オブジェクトの内部状態を保存し、必要なときにオリジネーターが必要とする内部状態を提供する役割を果たします

● Caretaker メモ管理者ロール (単純な Javabean) は、
メモを管理、保存、および提供します。
使用シナリオ:
● データの保存と復元が必要な関連する状態のシナリオ。
● ロールバック操作を提供します。
● 監視する必要があるレプリカ シナリオの場合。
● データベース接続のトランザクション管理はメモモードを使用します。
注:
●メモの有効期間
●メモのパフォーマンス
バックアップが頻繁に作成されるシナリオ (for ループなど) では、メモ モードを使用しないでください。
クローンモードメモ:
● イニシエーターロールは、イニシエーターロールとメモロールを組み合わせた二重の機能を持つ
マルチステートメモモード
●backupProp でイニシエーターの全属性値をメモに便利な HashMap に変換する BeanUtils クラスを追加役割のストレージ。restoreProp メソッドは、HashMap 内の値をイニシエーター ロールに返します。
BeanUtil ツールのクラス コード:

public class BeanUtils {
 //把 bean 的所有属性及数值放入到 Hashmap 中
 public static HashMap<String,Object> backupProp(Object bean){
 HashMap<String,Object> result = new
HashMap<String,Object>();
 try {
 //获得 Bean 描述
 BeanInfo
beanInfo=Introspector.getBeanInfo(bean.getClass());
 //获得属性描述
 PropertyDescriptor[]
descriptors=beanInfo.getPropertyDescriptors();
 //遍历所有属性
 for(PropertyDescriptor des:descriptors){
 //属性名称
 String fieldName = des.getName();
 //读取属性的方法
 Method getter = des.getReadMethod();
 //读取属性值
 Object fieldValue=getter.invoke(bean,new
Object[]{});
 if(!fieldName.equalsIgnoreCase("class")){
 result.put(fieldName, fieldValue);
 }
 }
 } catch (Exception e) {
 //异常处理
 }
 return result;
 }
 //把 HashMap 的值返回到 bean 中
 public static void restoreProp(Object bean,HashMap<String,Object>
propMap){
try {
 //获得 Bean 描述
 BeanInfo beanInfo =
Introspector.getBeanInfo(bean.getClass());
 //获得属性描述
 PropertyDescriptor[] descriptors =
beanInfo.getPropertyDescriptors();
 //遍历所有属性
 for(PropertyDescriptor des:descriptors){
 //属性名称
 String fieldName = des.getName();
 //如果有这个属性
 if(propMap.containsKey(fieldName)){
 //写属性的方法
 Method setter = des.getWriteMethod();
 setter.invoke(bean, new
Object[]{propMap.get(fieldName)});
 }
 }
 } catch (Exception e) {
 //异常处理
 System.out.println("shit");
 e.printStackTrace();
 }
 } }

複数のバックアップを含むメモ: カプセル化が若干改善されました: 作成者のみが読み取れるようにします。 空
のインターフェイス IMemento (メソッド属性を持たないインターフェイス) を作成し、
作成者クラス内に組み込みクラス (クラス内のクラスとも呼ばれます) を作成します。 Memento は IMemento インターフェイスを実装し、独自のビジネス ロジックも実装します。

19. ビジター パターンの定義
: オブジェクト構造の要素に対して実行される操作を表します。ビジターを使用すると、
操作対象の要素のクラスを変更せずに新しい操作を定義できます。これらの要素を変更せずに新しい操作を定義できます。 ● Visitor - 訪問者がどの要素にアクセスできるかを宣言する抽象訪問者抽象クラスまたは
インターフェイス
。具体的には、プログラムでは、visit メソッドのパラメータによってどのオブジェクトにアクセスできるかを定義します。
● ConcreteVisitor——特定の訪問者
訪問者が何をすべきか、授業を訪問した後に何をすべきかに影響します。
● 要素 - 抽象要素
インターフェイスまたは抽象クラス。どのタイプの訪問者を受け入れるかを宣言し、accept メソッドのパラメータを通じてプログラムで定義されます。
● ConcreteElement - 具体要素は
accept メソッド (通常は visitator.visit(this)) を実装し、基本的にパターンを形成します。
● ObjectStruture — 構造
オブジェクト 要素ジェネレーターは通常、List、Set、Map などの異なるクラスおよびインターフェイスの複数のコンテナーに収容されます。プロジェクトでは、この役割が抽象化されることはほとんどありません。
使用するシーン:
● オブジェクト構造には、さまざまなインターフェイスを持つ多数のクラス オブジェクトが含まれており、これらのオブジェクトに対して特定のクラスに依存する操作を実装したい場合、つまり、イテレータ モードでは十分ではない状況です。
● オブジェクト構造内のオブジェクトに対して多くの異なる関連性のない操作を実行する必要があるため、これらの操作によってオブジェクトのクラスが「汚染」されることを避けたいと考えます。

20. 状態モード (複合)
定義: 内部状態が変化するときにオブジェクトがその動作を変更できるようにします。オブジェクトはそのクラスを変更したように見えます。そのクラス。)
● 状態 — 抽象状態の役割 オブジェクト
を担当するインターフェイスまたは抽象クラス。状態定義、および状態切り替えを実現するための環境ロールのカプセル化。
● ConcreteState — 具体的なステートの役割
各具体的なステートは、ステートの動作管理とトレンドステートの処理という 2 つの責任を完了する必要があります。平たく言えば、ステート内で実行することと、ステートが他のステートにどのように遷移するかです。
● コンテキスト - 環境の役割
クライアントが必要とするインターフェイスを定義し、特定の状態の切り替えを担当します。
使用シナリオ:
● 状態の変化に応じて動作が変化するシナリオ
これは、権限設計などの状態パターンの基本的な開始点でもあります。異なる状態にある人は、同じ動作を実行したとしても、異なる結果になります。この場合、あなたは、状態パターンの使用を検討する必要があります。
● 条件文や分岐判定文の代替 注
:
ステートモードは、オブジェクトの状態が変化し、動作も大きく変化する場合、つまり動作が状態によって制約される場合に適しています。これを使用するときは、
オブジェクトの状態が 5 つを超えないようにすることが最善です。

21. インタプリタ パターンの定義
: 言語が与えられたら、その文法の表現を使用するインタプリタとともに、その言語の文を解釈するインタプリタを定義します (言語が与えられると、その表現の
文法を定義し、その表現を使用するインタプリタを定義します)。 )
● AbstractExpression — 抽象インタプリタ
特定の解釈タスクは各実装クラスによって完了され、特定のインタプリタはそれぞれ TerminalExpression と
Non-terminalExpression Finish で構成されます。
● TerminalExpression—ターミナル式は、
文法内の要素に関連付けられた解釈操作を実装します。通常、インタープリタ モードではターミナル式は 1 つだけですが、異なるターミナルに対応するインスタンスが複数存在します。この例に特有なのは VarExpression
クラスで、式内の各終端記号はスタック上に VarExpression オブジェクトを生成します。
● NonterminalExpression — 非終端記号式
文法内の各ルールは非終端式に対応しており、この具体例では、加算と減算のルールはそれぞれ AddExpression と SubExpression の 2 つのクラスに対応しています。非終端表現は
ロジックの複雑さに応じて増加し、原則として各文法規則が非終端表現に対応します。
● コンテキスト - 環境の役割
この例に特有なのは、代わりに HashMap を使用することです。
使用シナリオ:
● インタープリター モードは、繰り返し発生する問題に使用できます
。 ● 簡単な構文を説明する必要があるシナリオ
注:
重要なモジュールではインタープリター モードを使用しないようにしてください。そうしないと、メンテナンスに大きな問題が発生します。プロジェクトでは、Java コンパイル言語の欠点を補うために、インタプリタ モードの代わりにシェル、JRuby、Groovy などのスクリプト言語を使用できます。

22. フライウェイト パターン
定義: 共有を使用して、多数のきめの細かいオブジェクトを効率的にサポート
します (共有オブジェクトを使用すると、多数のきめの細かいオブジェクトを効果的にサポートできます)
。外部状態(外部)。
● 内部状態 内部
状態は、オブジェクトが共有できる情報であり、フライウェイト オブジェクト内に保存され、環境によって変化することはありません。
● 外部状態
外部状態とは、オブジェクトが依存できる目印であり、環境によって変化する共有できない状態です。
● フライウェイト — 抽象的なフライウェイトの役割
これは単に製品の抽象クラスであり、同時にオブジェクトの外部状態と内部状態のインターフェイスまたは実装を定義します。
● ConcreteFlyweight —— コンクリート フライウェイト ロール
抽象ロールによって定義されたビジネスを実装する特定の製品クラス。このロールで注意する必要があるのは、内部状態の処理は環境とは無関係であることです。外部状態を変更しながら内部状態を変更する操作は絶対に許可されません。
● unsharedConcreteFlyweight - 非共有フライウェイト ロール
共有テクノロジを使用できない外部状態またはセキュリティ要件 (スレッド セーフなど) を持たないオブジェクトは、通常、フライウェイト ファクトリには表示されません。
● FlyweightFactory — フライウェイト ファクトリ
役割は非常に単純です。つまり、プール コンテナを構築し、プールからオブジェクトを取得するメソッドを提供することです。
フライウェイト ファクトリのコード:
public class FlyweightFactory {
//プールコンテナを定義する
private static HashMap pool= new
HashMap();
//Flyweight ファクトリ
public static Flyweight getFlyweight(String Extrinsic){ //返される必要があるオブジェクトFlyweight flyweight = null; //そのようなオブジェクトはありませんプール内if (pool.containsKey(Extrinsic)){ flyweight = pool.get(Extrinsic); }else{ //外部状態に従ってフライウェイト オブジェクトを作成flyweight = new ConcreteFlyweight1(Extrinsic); //それをpool pool.put(Extrinsic, flyweight); } return flyweight; } }使用シナリオ: ● システム内には類似したオブジェクトが多数あります。● きめの細かいオブジェクトは比較的近い外部状態を持ち、内部状態は環境とは何の関係もありません。つまり、オブジェクトは特定のアイデンティティを持ちません。● バッファプールが必要なシナリオ。注: ● Flyweight モードはスレッド セーフではありません。経験にのみ依存し、必要に応じてスレッド セーフを考慮し、ほとんどのシナリオでは考慮する必要はありません。オブジェクト プールには、十分な数が満たされるまで、できるだけ多くのフライウェイト オブジェクトが存在します。



















● パフォーマンスの安全性: String や int などの Java の基本型を使用して外部状態をマークすると、効率が向上します。

23. ブリッジ パターンの定義
: 抽象化をその実装から切り離し、2 つが独立して変化できるようにします
● インプリメンタ — 実装ロールこれは、ロールの必要な動作と属性を定義するインターフェイスまたは抽象クラスです。● RefinedAbstraction ——洗練された抽象化ロール抽象化ロールを改訂する実現ロールを指します。● ConcreteImplementor — 具体的な実装の役割インターフェイスまたは抽象クラスによって定義されたメソッドとプロパティを実装します。使用するシナリオ: ● 継承が予期されない、または適用できないシナリオ● インターフェイスまたは抽象クラスが不安定なシナリオ● 高い再利用性が必要なシナリオ注:クラス継承に N 層があることがわかった場合は、ブリッジ モードの使用を検討できます。 。ブリッジ パターンでは、主に抽象化と実装をどのように分割するかを考慮します。設計原則:単一責任の原則: 単一責任の原則単一責任の原則の利点は次のとおりです。

















● クラスの複雑さが軽減され、責任が明確に定義される;
● 可読性が向上し、複雑さが軽減されるため、当然可読性が向上します;
● 保守性が向上し、当然可読性が向上します維持が容易である;
● 変更によるリスクが軽減され、変更が不可欠である インターフェースの単一責任が適切に行われている場合、インターフェースの変更は対応する実装クラスにのみ影響し、他のインターフェースには影響を与えません。 、システムの拡張に影響を与えるため、セクシュアリティと保守性は非常に役立ちます。
ps: インターフェイスの責任は 1 つだけである必要があり、変更の理由が 1 つだけになるようにクラスの設計を設計する必要があります。
単一責任の原則は、「責任」または「変更の理由」を使用してインターフェイスまたはクラスが適切に設計されているかどうかを測定する、プログラムを作成するための標準を提案しますが、「責任」と「変更の理由」は測定可能ではなく、プロジェクトごとに異なります。プロジェクト環境によって異なります。
● Liskov 置換原則: Liskov 置換原則定義: 基本クラスへのポインタまたは参照を使用する関数は、それを知らずに派生クラスのオブジェクトを使用
できなければなりません(基本クラスへのすべての参照は、そのサブクラスのオブジェクトを透過的に使用できなければなりません)。平たく言えば、親クラスが出現できればサブクラスも出現でき、サブクラスに置き換えてもエラーや例外は発生しないため、ユーザーはそれが親クラスなのかサブクラスなのかを知る必要はないかもしれません。ただし、その逆は不可能で、サブクラスが存在する場合、親クラスは適応できない可能性があります。この定義に含まれる 4 つの意味は次のとおりです。1. サブクラスは親クラスのメソッドを完全に実装する必要がある2. サブクラスは独自の個性を持つことができる3. 親クラスのメソッドをオーバーライドまたは実装するときに入力パラメーターを拡大できる







親クラスの入力パラメータの型がサブクラスの入力パラメータの型より大きい場合、親クラスは存在してもサブクラスが存在しない可能性があります。これは、サブクラスがパラメータとして渡されると、呼び出し元がサブクラスのメソッドカテゴリに入る可能性があります。

  1. 親クラスのメソッドをオーバーライドまたは実装すると、出力結果を削減できます。
    親クラスのメソッドの戻り値は T 型で、サブクラスの同じメソッド (オーバーロードまたはオーバーライド) の戻り値はS の場合、リスコフ置換原理 S は T 以下である必要があります。つまり、S と T が同じ
    型であるか、S が T のサブクラスであるかのいずれかです。
    ● インターフェイス分離の原則: インターフェイス分離の原則
    インターフェイスには次の 2 種類があります:
    オブジェクト インターフェイス: Java のクラスもインターフェイスです。 クラス
    インターフェイス:
    Interface キーワードによって定義されるインターフェイスの分離は、Java でよく使用されます。単一のインターフェイスを確立するには、肥大化した巨大なインターフェイスを作成しないでください。つまり、インターフェイスはできるだけ詳細にし、インターフェイス内のメソッドは最小限にする必要があります。
    インターフェイス分離の原則と単一責任の原則の違い: インターフェイス分離の原則は、単一責任の観点からは異なります。単一責任は、ビジネス ロジックの
    分割インターフェイス分離の原則ではインターフェイスのメソッドができる限り少ないことが必要です。
    ● 依存性逆転の原則:Dependency Inversion Principle
    本来の定義:
    ①高レベルのモジュールは低レベルのモジュールに依存すべきではなく、両方ともその抽象化に依存すべきである、
    ②抽象化は詳細(実装クラス)に依存すべきではない、
    ③詳細は抽象化に依存すべきである。 。
    Java 言語における依存関係逆転原理の具体化:
    ①モジュール間の依存関係は抽象化を通じて発生し、実装クラス間に直接の依存関係はなく、依存関係は
    インターフェースまたは抽象クラスを通じて生成される;
    ②インターフェースまたは抽象クラスは依存しない実装クラス;
    ③ 実装クラスはインターフェースまたは抽象クラスに依存します。
    依存関係を記述する 3 つの方法:
    ①コンストラクターが依存オブジェクトを転送する (コンストラクター インジェクション)
    ②セッター メソッドが依存オブジェクトを転送する (セッター依存関係インジェクション)
    ③インターフェイスが依存オブジェクトを宣言する (インターフェイス インジェクション)
    使用原則:
    依存関係逆転の原則の本質は、抽象化 (インターフェイスまたは抽象クラス)は、各クラスまたはモジュールの実装を互いに独立させ、相互に影響を与えず、モジュール間の疎結合を実現します。このルールをプロジェクトでどのように使用しますか?
    以下のルールに従ってください:
    すべてのクラスは、可能な限りインターフェイスか抽象クラス、あるいは抽象クラスとインターフェイスの両方を持つべきです ②変数の表面型は可能な限り
    インターフェイスか抽象クラスでなけれ④基底クラスのメソッドを上書きしないようにする⑤リスコフ置換原則と組み合わせて使用​​する オープンクローズド原則:オープンクローズド原則の定義:ソフトウェアエンティティは次のことを行う必要があります。拡張機能の閉鎖に対してオープンであること。その意味するところは、ソフトウェア エンティティは既存のコードの変更ではなく、拡張機能を通じて変更を実装する必要があるということです。ソフトウェア エンティティ: プロジェクトまたはソフトウェア製品内の特定の論理ルールに従って分割されたモジュール、抽象化、クラス、およびメソッド。3種類の変更: ①ロジック​​変更他のモジュールを介さずロジックを1つだけ変更する 例えば、元のアルゴリズムはb+cだったのを、b*cに変更するなど、元のメソッドを変更することができます。 class 前提条件は、すべての依存クラスまたは関連クラスが同じロジックに従って処理されるということです。② サブモジュールの変更












    モジュールの変更は他のモジュールに影響を与えます。特に低レベルのモジュールの変更は必然的に高レベルのモジュールの変更を引き起こすため、拡張によって変更が完了すると、高レベルのモジュールの変更が避けられません。
    ③ 可視ビューの変更
    可視ビューとは、JSP プログラムや Swing インターフェイスなど、顧客に提供するインターフェイスです。この部分の変更は一般に連鎖反応を引き起こします (特に国内プロジェクトでは、欧州でのアウトソーシング プロジェクトでは一般に
    あまり)。オリジナルの設計が柔軟であるかどうかに応じて、拡張による変更が可能です。

おすすめ

転載: blog.csdn.net/dreamer23/article/details/109356679