デザイン パターン (デザイン パターン) は、ほとんどの人に知られている、繰り返し使用されるコード設計エクスペリエンスを分類してカタログ化した一連の概要です。
デザインパターンは3種類に分かれており、合計23種類あります。
紅陽、ルーキーチュートリアルなどの記事を参考に執筆。間違いがあれば修正してください。違反がある場合は削除しますのでご連絡ください。
1. デザインパターン Observer Pattern (Observer Pattern) WeChat 公共サービスを例に取る
2. デザインパターン Factory Pattern (ファクトリーパターン) は Rojiamo の販売から始まります
3. デザインパターン シングルトンデザインパターン (シングルトンパターン) 完全解析
4. デザインパターン ロールゲームを背景とした戦略パターン(Strategy Pattern)
5. デザインパターン アダプターパターン(Adapter Pattern) 携帯電話の充電器を例に挙げます。
6. スマート家電を管理するためのデザインパターン コマンドパターン
7. デザインパターン Decorator Pattern はあなたを伝説の世界に連れ戻します
8. デザインモード、外観モード(ファサードパターン)ワンクリックムービーモード
9. デザインパターンテンプレートメソッドパターンはプログラマーの一日を表します
10. デザインパターン ステートパターン(State Pattern) 自動販売機を例に挙げます
11. デザインパターン ビルダーパターン(Builder Pattern) 車を作る、車を買うを例に挙げます。
12. デザインパターン プロトタイプパターン(Prototype Pattern) 複数の形状を取得する場合を例に挙げます
13. 設計パターン Flyweight Pattern (Flyweight Pattern) では、複数の形状をランダムに取得する例を取り上げます。
14. デザインパターン プロキシパターン (Proxy Pattern) ディスクから画像を取得する場合を例に挙げます。
15. デザインパターン Bridge Pattern(ブリッジパターン) 異なる色の円を描く例を取り上げます。
16. デザインパターンの組み合わせパターン(複合パターン) 従業員階層の作成と印刷を例にします
17. デザインパターン Iterator Pattern (Iterator Pattern) イテレータを使用して名前を出力する例を取り上げます。
18. デザインパターン Mediator Pattern (Mediator Pattern) パブリックチャットルームを例に取る
19. デザインパターン Mementoパターン(Memento Pattern) Mementoを例に挙げます
20. デザインパターン インタプリタパターン (Interpreter Pattern) 文章の説明を例に挙げます
21. デザインパターン 責任連鎖パターン(Chain of Responsibility Pattern) Android Studioでのログ印刷を例にします
22. デザインパターン Visitor Pattern (Visitor Pattern) コンピュータのコンポーネントの表示を例に挙げます。
- オブザーバー
- 工場
- シングルトン
- 戦略
- アダプタ
- 指示
- デコレータ
- ファサード
- テンプレートメソッド
- 州
- ビルダー
- プロトタイプ
- フライ級
- プロキシ
- 橋
- 複合
- イテレータ
- 調停者
- メメント
- 責任の連鎖
- ビジター
オブジェクト間の 1 対多の依存関係を定義します。これにより、オブジェクトが変更されると、そのすべての依存関係が通知され、自動的に更新されます。
JDK や Andorid には、XXXView.addXXXListenter など、オブザーバー パターンを実装する場所が数多くあります。 もちろん、オブザーバー パターンは 1 対多の関係であり、setXXXListener の場合、XXXView.setOnXXXListener が必ずしもオブザーバー パターンであるとは限りません。 1 と 1 の関係はコールバックと呼ばれます。
特別なインターフェイス: Subject.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
3Dサービスアカウントの実装クラス:ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
すべてのオブザーバーは、このインターフェース Observer.java を実装する必要があります。
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
最終テスト: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
このパターンのファミリーを簡単にリストしてみましょう。
1. 静的ファクトリーモード
2. シンプルファクトリーモード(ストアでRojiamoを購入)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3.ファクトリーメソッドモデル(支店開設)
Rojia MoStore を作成するための抽象メソッドを提供します: RoojiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
抽象メソッドの具体的な実装: XianRojiaMoStore.java
ブランチは依然として単純なファクトリ モデル XianSimpleRojiaMoFactory.java を使用しています。
4. 抽象的な工場パターン(公式原材料を使用)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
シングルトン モードは主に、複数のインスタンスの作成によって発生するリソースの無駄を回避するためのものであり、複数のインスタンスが複数の呼び出しによって誤った結果につながる可能性があります。シングルトン モードを使用すると、アプリケーション全体にインスタンスが 1 つだけ存在することが保証されます。
定義: オブジェクトの一意性を保証するために必要な手順は 3 つだけです
定義の比較:
ハングリーハンスタイル [利用可能]: SingletonEHan.java
遅延 Han スタイルが含まれています [二重検証ロックを推奨]: SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
戦略パターン: アルゴリズムのファミリーを定義し、それらを個別にカプセル化して、アルゴリズムを使用する顧客に依存せずにアルゴリズムを変更できるようにします。
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
定義: クラスのインターフェイスを、クライアントが期待する別のインターフェイスに変換します。アダプターは、互換性のないインターフェイスを持つクラスが相互に連携できるようにします。この定義は問題ありません。アダプターの機能は、あるインターフェイスを別のインターフェイスに変換することです。
充電器を例に挙げると、携帯電話の充電器は一般的に 5V 程度です。中国の家庭用 AC 電圧は 220V なので、携帯電話の充電にはアダプター (電圧降下器) が必要です。
携帯電話: Mobile.java
電話機は、5V 電圧を提供するインターフェイス V5Power.java に依存しています。
私たちが持っているのは 220V の家庭用 AC: V220Power.java です。
220V を 5V に変換する機能を完了するアダプター: V5PowerAdapter.java
最終テスト: 電話を充電します:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
定義: 「リクエスト」をオブジェクトにカプセル化し、別のリクエスト、キュー、またはログを使用して他のオブジェクトをパラメータ化できるようにします。コマンド モードでは、取り消し可能な操作もサポートされています。 (簡略化: リクエストをオブジェクトにカプセル化し、アクションリクエスタとアクションエグゼキュータを分離します。)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
デコレータ パターン: 機能を拡張するために、デコレータは統合に代わるより柔軟な手段を提供し、責任をオブジェクトに動的に割り当てます。
クラスを設計するときに、このクラスにいくつかの補助関数を追加する必要があるが、このクラスのコードを変更したくない場合に、デコレータ パターンが登場します。遊びましょう。これは、クラスは拡張に対してオープンであり、変更に対してクローズであるべきであるという原則を反映しています。
要件: ゲームの装備システムを設計する基本的な要件は、さまざまな宝石を埋め込んだ後の各装備の攻撃力と説明を計算できることです。
1. スーパークラスの機器: IEquip.java
2. 各機器の実装クラス:
3. 装飾のスーパークラス (装飾は機器にも属します): IEquipDecorator.java
4. 装飾の実装クラス:
5. 最終テスト: 攻撃力を計算し、説明を表示します:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
定義: サブシステム内のインターフェイスのグループにアクセスするための統一インターフェイスを提供します。外観は、サブシステムを使いやすくするための高レベルのインターフェイスを定義します。実際、顧客の利便性を考慮して、一連の操作が 1 つのメソッドにカプセル化されています。
需要: 私は映画を見るのが好きなので、プロジェクター、コンピューター、ステレオを購入し、部屋の照明を設計し、ポップコーンマシンを購入しました。そして、映画を見たいときは、ワンクリックで視聴し、ワンクリックでシャットダウンする必要があります。 。
各デバイスクラスのスイッチおよびその他の操作:
例: ポップコーンマシン: PopcornPopper.java
シネマクラス: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
最終テスト: ワンクリックで映画を視聴:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
定義: アルゴリズムのスケルトンを定義し、一部のステップをサブクラスに延期します。テンプレート メソッドを使用すると、アルゴリズムの構造を変更せずにサブクラスがアルゴリズムのステップを再定義できます。
要件: 簡単に説明します: 当社にはプログラマー、テスター、人事、プロジェクト マネージャーなどがいます。以下ではテンプレート メソッド モードを使用して、全担当者の作業状況を記録します。
テンプレートメソッドパターンにおける3種類の役割
1. 具体的な方法
2. 抽象メソッド
3. フック方式
ワーカースーパークラス: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
プログラマ実装クラス(時間が分かる):ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
最終テスト:
全員がどのように働いているかを確認してください。
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
プログラマーがいつ会社を辞めたかを確認します。
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
定義: オブジェクトの内部状態が変化したときにオブジェクトの動作を変更できるようにし、オブジェクトがそのクラスを変更したかのように見せます。
オブジェクトの内部状態が変化すると、同様のものが再初期化されるように見えます。
要件:自動販売機を例にします(コイン投入・未投入などの状態、コイン投入・返却方法あり)
改善される自動販売機の初期実装: VendingMachine.java
改良された自動販売機 (柔軟性が向上): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
状態インターフェイス: State.java
状態に対応するインターフェース実装クラス:
自動販売機テストの改善:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
構築モードはオブジェクト作成モードです。構築モードでは、製品の内部表現を製品の製造プロセスから分離できるため、構築プロセスで異なる内部表現を持つ製品オブジェクトを生成できます。
要件: ユーザーは車を購入するために自動車店に行きます。
分析:カーショップは各ユーザーのニーズに応じて該当する車を抽出します
ビルダーのスーパークラス: ビルダー
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
ビルダー対応実装クラス:ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
店長が車を引き取ります。
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
プロトタイプ パターンは、パフォーマンスを確保しながら繰り返しオブジェクトを作成するために使用されます。このタイプのデザイン パターンは創造的なパターンであり、オブジェクトを作成するための最適な方法を提供します。
このパターンは、現在のオブジェクトのクローンを作成するために使用されるプロトタイプ インターフェイスを実装します。このモードは、オブジェクトを直接作成するコストが比較的高い場合に使用されます。たとえば、高価なデータベース操作の後にオブジェクトを作成する必要があります。オブジェクトをキャッシュし、次のリクエストでそのクローンを返し、必要に応じてデータベースを更新してデータベース呼び出しを減らすことができます。
複数の形状を取得する場合を例に挙げると、次の 4 つの手順があります。
1. Cloneable インターフェイスを実装する抽象クラスを作成します。形状(クローン可能を実装)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2. 上記の抽象クラスを拡張するエンティティ クラスを作成します。円、長方形、正方形
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. データベースからエンティティ クラスを取得し、ハッシュテーブルに格納するクラスを作成します。シェイプキャッシュ
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4. ShapeCache クラスを使用して、ハッシュテーブルに保存されている形状のクローンを取得します。
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
主に、作成されるオブジェクトの数を減らしてメモリ使用量を削減し、パフォーマンスを向上させるために使用されます。このタイプのデザイン パターンは構造パターンであり、オブジェクトの数を減らし、アプリケーションに必要なオブジェクト構造を改善する方法を提供します。
Flyweight パターンは、同じタイプの既存のオブジェクトを再利用するか、一致するオブジェクトが見つからない場合は新しいオブジェクトを作成しようとします。さまざまな場所に 20 個の円を描く 5 つのオブジェクトを作成して、このパターンを示します。使用できる色は 5 色のみであるため、color プロパティを使用して既存の Circle オブジェクトを確認します。
複数の形状をランダムに取得する場合を例に挙げると、次の 4 つのステップがあります。
1. インターフェースを作成します。
public interface Shape {
void draw ();
}
2. インターフェイスを実装するエンティティ クラスを作成します。
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3. 与えられた情報に基づいてエンティティ クラスのオブジェクトを生成するファクトリを作成します。
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4. このファクトリを使用して、色情報を渡してエンティティ クラスのオブジェクトを取得します。
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
あるクラスは別のクラスの機能を表します。プロキシ パターンでは、外部への機能インターフェイスを提供するために、既存のオブジェクトを使用してオブジェクトを作成します。メモリ内にそのようなオブジェクトが存在しない場合は作成され、存在する場合は直接オブジェクトが返されることがわかります。
ディスクから写真を取得する場合を例に挙げると、合計 3 つの手順があります。
1. インターフェースを作成します。
public interface Image {
void display ();
}
2. インターフェイスを実装するエンティティ クラス RealImage を作成します。対応するプロキシ クラス: ProxyImage。
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3. 要求されたら、ProxyImage を使用して RealImage クラスのオブジェクトを取得します。
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
Bridge は、抽象化と実装を分離して、この 2 つが独立して変更できるようにするために使用されます。このタイプのデザイン パターンは構造パターンであり、抽象化と実装の間に橋渡し構造を提供することでそれらを切り離します。
異なる色の円を描画する場合を例として、実装は 5 つのステップに分かれています。
1. ブリッジ実装インターフェイスを作成します。
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. DrawAPI インターフェイスを実装するエンティティ ブリッジ実装クラスを作成します。赤丸、緑丸
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3. DrawAPI インターフェイスを使用して、抽象クラス Shape を作成します。
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. Shape インターフェイスを実装するエンティティ クラスを作成します。
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5. Shape クラスと DrawAPI クラスを使用して、さまざまな色の円を描画します。
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
部分全体パターンとも呼ばれ、類似したオブジェクトのグループを 1 つのオブジェクトとして扱うために使用されます。合成モードでは、部分階層と全体階層を表すために使用されるツリー構造に従ってオブジェクトが結合されます。このタイプのデザイン パターンは構造パターンであり、オブジェクトのグループのツリー構造を作成します。
従業員階層の作成と印刷を例として、最小単位の例を示します。
1. Employee オブジェクトのリストを含む Employee クラスを作成します。
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2. Employee クラスを使用して、従業員階層を作成および印刷します。
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
Java および .Net プログラミング環境で非常に一般的な設計パターン。このパターンは、コレクション オブジェクトの基礎となる表現を知らなくても、コレクション オブジェクトの要素に順番にアクセスするために使用されます。イテレータ パターンは動作パターンです。
例としてイテレーターを使用して名前を出力する場合、合計 3 つのステップがあります。
1. インターフェースを作成します。
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. Container インターフェイスを実装するエンティティ クラスを作成します。このクラスには、Iterator インターフェイスを実装する内部クラス NameIterator があります。
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3. NameRepository を使用してイテレータを取得し、名前を出力します。
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
複数のオブジェクトとクラス間の通信の複雑さを軽減するために使用されます。このパターンは、通常、異なるクラス間の通信を処理し、疎結合をサポートする中間クラスを提供するため、コードの保守が容易になります。メディエーター モデルは動作モデルです。
パブリック チャット ルームを例に挙げると、最小単位の手順例は次のとおりです。
1. 中間クラスを作成します。
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. ユーザークラスを作成します。
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3. User オブジェクトを使用して、それらの間の通信を表示します。
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
オブジェクトの特定の状態を保存して、適切なときに復元できるようにします。メモモードは動作モードです。
メモを使用する場合の最小単位ステップは次のとおりです。
1. Memento クラスを作成します。
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2. Originator クラスを作成します。
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3. CareTaker クラスを作成します。
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4. CareTaker オブジェクトと Originator オブジェクトを使用します。
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
言語の文法や表現を評価する方法を提供するものであり、動作パターンです。このパターンは、特定のコンテキストを解釈する式インターフェイスを実装します。このモードは、SQL 解析、シンボル処理エンジンなどで使用されます。
文の説明を例として、最小単位ステップは次のとおりです。
1. 式インターフェイス Expression を作成します。
public interface Expression {
public boolean interpreter ( String content );
}
2. 上記のインターフェイスを実装するエンティティ クラスを作成します。 TerminalExpression、OrExpression、AndExpression。
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3. Expression クラスを使用してルールを作成し、それらを解析します。
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
Chain of Responsibility パターンは、リクエストの受信者オブジェクトのチェーンを作成します。このパターンは、リクエストのタイプに基づいてリクエストの送信者と受信者を分離します。このタイプの設計パターンは動作パターンです。このパターンでは、通常、各レシーバーに別のレシーバーへの参照が含まれます。オブジェクトがリクエストを処理できない場合は、同じリクエストを次の受信者に渡します。
Android Studio でログを印刷する場合を例に挙げると、最小単位のステップは次のとおりです。
1. 抽象ロガー クラス AbstractLogger を作成します。
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. ロガー クラスを拡張するエンティティ クラスを作成します。
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3. さまざまなタイプのロガーを作成します。異なるエラー レベルを与え、各ロガー内で次のロガーを設定します。各ロガー内の次のロガーはチェーンの一部を表します。
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
ビジター パターンでは、要素クラスの実行アルゴリズムを変更するビジター クラスを使用します。このようにして、要素の実行アルゴリズムは、訪問者の変化に応じて変化する可能性があります。このタイプの設計パターンは動作パターンです。スキーマによれば、要素オブジェクトはビジター オブジェクトを受け入れているため、ビジター オブジェクトは要素オブジェクトに対する操作を処理できます。
ディスプレイ コンピュータのコンポーネントを例に挙げると、主に次の 5 つのステップで実装されます。
1. 要素を表すインターフェイスを定義します。
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. 上記のクラスを拡張するエンティティ クラスを作成します。キーボード、モニター、マウス、コンピューター
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3. 訪問者を表すインターフェースを定義します。
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. 上記のクラスを実装するエンティティ訪問者を作成します。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5. ComputerPartDisplayVisitor を使用して、Computer のコンポーネントを表示します。
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/