ホームページ > Java > &#&チュートリアル > Javaの一般的なデザインパターン

Javaの一般的なデザインパターン

高洛峰
リリース: 2016-12-12 13:32:52
オリジナル
1204 人が閲覧しました

Java デザイン パターン;
Java デザイン パターンに関するプログラマーの理解:
非常に単純なものをなぜこれほど複雑にする必要があるのか​​が「わかりません」。その後、ソフトウェア開発の経験が増えるにつれて、私が見た「複雑さ」こそがデザイン パターンの本質であることがわかり始めました。私が「単純さ」として理解していたのは、鍵を使用して錠を開けるパターンでした。目的は、現在の問題を解決するために、すべてのロックを解除するソリューションを提案する目的で「マスター キー」を構築するという点に、設計パターンの「複雑さ」があります。デザインパターンを本当に理解する前は、「シンプル」なコードを書いていました
この「シンプル」というのは、機能のシンプルさではなく、デザインのシンプルさです。シンプルなデザインは柔軟性に欠けることを意味し、このプロジェクトでしか役に立たないコードは「使い捨てコード」と呼ばれます。

-->コードを再利用可能にするには、「デザイン パターン」を使用してコードを設計してください

私の知っているプログラマーの多くは、デザイン パターンを学んだ後に後悔していると言う人もいます。まるで自分が生まれ変わって新しいレベルに到達したかのように感じ、プログラマーのレベルを分類する基準としてデザインパターンを理解しているかどうかを考慮する人もいます。

私たちはパターンの罠に陥って、パターンを使用するためにパターンを適用することはできません。そうしないと、形式主義に陥ってしまいます。パターンを使用するときは、パターンの実装の詳細にはあまり注意を払うのではなく、パターンの意図に注意を払う必要があります。これらの実装の詳細は特定の状況下では変更される可能性があるためです。デザイン パターン ブック内のクラス図や実装コードがパターンそのものを表していると頑固に信じないでください。


設計原則: (重要)
1.
ロジック コードは、カプセル化に重点を置いて個別のメソッドに分割されており、読みやすく再利用しやすいです。
1 つのメソッドで数百行のロジック コードを記述しないでください。小さなロジックコードを一つ一つ分けて別のメソッドに記述すると、読みやすく繰り返し呼び出すことができます。
2.
クラス、メソッド、関数を作成するときは、移植性と再利用性を考慮する必要があります。ワンタイム コードを避けてください。
他の同様のものから入手できますか?他のシステムでも入手可能でしょうか?
3.
継承の考え方を上手に活用する:
アプリケーションの類似点や変更が難しいものを見つけ出し、それらを抽象クラスに抽出し、サブクラスに継承させます。あなた自身のロジックは他人の結果に基づいています。 ImageField は JTextField を拡張したものです。
インターフェースの考え方を上手に使用します。
アプリケーション内で変更が必要な可能性のある領域を見つけ出し、それらを分離し、変更する必要のないコードと混合しないでください。かわった。

非常に単純なものを非常に複雑にする、ワンタイムコード、デザインパターンの利点の例: (戦略モード)
説明:
シミュレーションアヒルゲームアプリケーション、要件: さまざまな色や形がゲームに表示されますアヒルは鳴き声を上げながら水中で泳いだり遊んだりします。

最初のメソッド: (ワンタイムコード)

さまざまなアヒルのクラスを直接記述します: MallardDuck//Wild duck、RedheadDuck//Red-headed duck それぞれのタイプに 3 つのメソッドがあります:
quack(): クワッキング メソッド。
swim( ): 水泳メソッド
display(): 外観メソッド

2 番目のメソッド: 継承された特性を使用して共通部分を改善し、プログラミングの繰り返しを回避します。

つまり、アヒルのスーパークラス (スーパークラス) を設計し、さまざまなアヒルにこのスーパークラスを継承させます。 CPUBLIC class duck {
public void quack () {// 呱
System.out.println ("呱 呱") ") ;
} b Public AbstratAct void Display ();/*見た目が違うので、サブクラスは自分で作ります。 */
}

そのサブクラスを継承し、独自の display() メソッドを実装するだけです。
//MallardDuck
public class MallardDuck extends Duck{
public void display(){
System.out.println("マガモの色...");

}

}
//アカガモ
public class RedheadDuck extends Duck {L public void display() {
system.out.println ("color of red-headed duck ...");私たちオブジェクト指向プログラマーにとって、これはこれ以上に簡単です。スーパークラスに 1 つ追加するだけです

方法は 1 つだけで十分です。 CPUBLIC class duck {
public void quack () {// 呱
System.out.println ("呱 呱") ") ;
}
public abstract void display(); /*見た目が違うので、サブクラスは自分たちで決定します。 */
public void fly(){
System.out.println("Fly! Duck");
}
}
飛べないアヒルの場合は、サブクラスで単純にオーバーライドするだけで済みます。
// 障害のあるアヒル
public class DisabledDuck extends Duck{
public void display(){
System.out.println("障害のあるアヒルの色...");
}
public void fly(){
/ /オーバーライドして何もしない状態になります。
}
}
他の飛んでいるアヒルはカバーする必要はありません。

このようにして、このスーパークラスを継承するすべてのアヒルが飛行します。しかし、問題が再び発生し、顧客は、飛べるアヒルと飛べないアヒルがいることを指摘しました。

> > はい、1 つのクラスが変更されると、別のクラスも変更されます。これは、OO の設計と少し矛盾します。これは明らかに結合しています。継承を使用する --> 結合度が高すぎる

3 番目の方法:

インターフェースの改善を使用する。

変更されやすい部分を抽出し、カプセル化して将来の変更に対応します。コード量は増えましたが、結合度が減り使い勝手が向上しました。

fly メソッドを抽出し、Duck をクックします。

パブリック インターフェイス Flyable{
public void fly();
}

パブリック インターフェイス Quackable{

public void quack();
}
Duck の最終設計は次のようになります:
public class Duck{
public void swim(){ //水泳 O System.out.println("水泳");
}
Public Abstract void void display(); /*見た目が違うのでサブクラスを決定します。 */
}
そして、MallardDuck、RedheadDuck、DisabledDuck は次のように書くことができます:
//Wild Duck
public class MallardDuck extends Duckimplements Flyable,Quackable{
public void display(){
System.out.println("The color of野生のアヒル。 ..");
}
public void fly(){
//このメソッドを実装します
}
public void quack(){
}
//このメソッドを実装します }
}
// duck
public class RedheadDuck extends Duckimplements Flyable,Quackable{
public void display(){
System.out.println("The color of red-headed duck...");
}
public void fly(){
//このメソッドを実装します
}
public void quack(){
//このメソッドを実装します
}
}
//Disabled Duck は Quackable のみを実装します (吠えることはできますが飛ぶことはできません)
public class DisabledDuck extends Duckimplements Quackable{
public void display(){
System.out.println ("足の不自由なアヒルの色...");
}
public void quack(){
//このメソッドを実装します
}
}

>>>>>>コメント:
利点:
このように設計されたプログラムは、それらの間の結合を軽減します。
短所:
Flyable インターフェースと Quackable インターフェースは最初は非常に優れているように見え、問題は解決されました (Flyable は飛行できるアヒルによってのみ実装できます)。しかし、Java インターフェースには実装コードがないため、インターフェースを実装してもコードの再利用は実現できません。

4 番目のメソッド:

上記のメソッドの要約:
継承の利点: 共通部分を再利用でき、プログラミングの繰り返しを回避できます。

継承の欠点: スーパークラスが新しいメソッドを追加すると、サブクラスによって継承されます。サブクラスのかなりの部分がこのメソッドを実装していない場合は、大量の変更が必要になります

。継承する場合、サブクラスは他のカテゴリを継承できません。

実装クラスが他のカテゴリやインターフェイスを継承できるようにするため、インターフェイスの利点はありません。この問題を解決するには、次の戦略パターンを使用できます。

----------------------- Strategy(strategy pattern ) -------------------------

私たちには次のような設計原則があります:

アプリケーション内で同じで変更が難しいものを見つけ出し、それらを抽象クラスに抽出し、サブクラスに継承させます。

アプリケーション内で変更が必要な可能性のある領域を見つけて分離し、変更する必要のないコードと混合しないでください。 -->重要。

ここで、「変化する部分と変化しない部分」を分離するために、(Duck クラスから完全に離れた) 2 つのクラスのセットを作成します。1 つは「fly」に関連し、もう 1 つは「fly」に関連するものです。 other

は "quack" に関連しており、クラスの各セットは独自のアクションを実装します。たとえば、「croaking」を実装するクラス、「squeaking」を実装する別のクラス、そして「quiet」を実装する別のクラスがあるとします。

最初に 2 つのインターフェイスを作成します。 FlyBehavior (飛行動作) と QuackBehavior (呼び出し動作)。
public Interface FlyBehavior{

public void fly();

}

public Interface QuackBehavior{

public void quack();

}

FlyBehavior の達成のためのいくつかの特定の関数を定義しています。 。

public class FlyWithWingsimplements FlyBehavior{

public void fly(){
//翼のあるすべてのアヒルの飛行動作を実装します。
}
}

public class FlyNoWay は FlyBehavior を実装します{

public void fly(){
// 何もしない、飛べません
}
}
QuackBehavior のいくつかの具体的な実装。
public class Quackimplements QuackBehavior{

Public void quack(){

//鳴くアヒルを実装する
}
}

public class Squeakimplements QuackBehavior{
public void quack(){
//鳴くアヒルを実装する
}
}

public class MuteQuack は QuackBehavior を実装します{
public void quack(){
//何もせず、叫びません
}
}

コメント 1:
この設計では、飛行およびクワッキングアクションが可能です他のオブジェクトによって再利用されます。行動はもはやアヒルクラスには関係ありません。そして、いくつかの新しい動作を追加しても、既存の動作クラスには影響せず、飛行動作を「使用する」アヒルのクラスにも影響しません。

最後に、Duck がどのようにデザインされているかを見てみましょう。 publicパブリッククラス{--------> out out'' out out out out out out out out out ''s ‐ ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ public Duck( ){}
public abstract void display();継承されたクラスの実装方法に応じて、対応するメソッドが呼び出されます
}
public void PerformQuack(){
quackBehavior.quack();();

}

}

MallardDuck のやり方をご覧ください。 & ----- & gt; メソッドを構築することで、「fly」、「called」の特定の属性を指定するために、「flying '、' called」の特定の実装クラスを生成します。
Public Class Mallardduck Extends Duck {
PUBLIC MALLALARDUCK {
{
{
flyBehavior = new FlyWithWings ();
quackBehavior = new Quack();
//MallardDuck は Duck を継承しているため、すべて flyBehavior と quackBehavior インスタンス変数を持ちます}
public void display(){
} / /Implement
}
}

以上です。満足したら、飛んだり、吠えたり、色を表示したりすることができます。


このデザインでは、flyBehavior と quackBehavior のインスタンス化がサブクラスに記述されていることがわかります。動的に決定することもできます。

Duck に 2 つのメソッドを追加するだけです。

コンストラクターでのプロパティへの値の割り当てとプロパティ セッターの使用の違い:

コンストラクターでのプロパティへの値の割り当て: 固定、不変

プロパティ セッターを使用すると、後で値を動的に変更できます。オブジェクトのインスタンス化が変更され、より柔軟になります。



public class Duck{
FlyBehavior flyBehavior;//インターフェイス
QuackBehavior quackBehavior;//インターフェイス
public void setFlyBehavior(FlyBehavior flyBehavior){
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior {
this.quackBehavior= quackBehavior;
}

}



---------------------- static Factory Method (静的ファクトリ) ----- --- -----------------
(1)

デザインパターンの中では、ファクトリーメソッドも比較的シンプルなものですが、広く使われているEJB、RMI、COM、CORBA、このパターン

の影は Swing で見ることができ、これは最も重要なパターンの 1 つであり、多くの場所で xxxFactory のような名前のクラスが見られます


(2)
基本概念:
FactoryMethod は創造性パターンです。オブジェクトを作成するためのインターフェイスを定義しますが、どのクラスをインスタンス化するかをサブクラスに決定させます。

通常、オブジェクトを作成する標準メソッドとしてファクトリ メソッドを使用します。

アプリケーションの側面:
どのような種類のオブジェクトを作成するか、またはクラスが予測できない場合。クラスが作成するオブジェクトを指定するためにサブクラスを必要とする場合、ファクトリ メソッド パターンを使用する必要があります。

---------- --------------- -------- singelton (シングルケースモード) ------------- ----------

基本概念:

シングルトンは、インスタンスが 1 つだけ生成されるようにするために使用され、それにアクセスするためのグローバル アクセス ポイントを提供するために使用されます。たとえば、データベースなど、インスタンスのみが非常に重要であることが保証されます。接続またはソケット接続には特定の制限があり、同時に存在する必要がある接続は 1 つだけです。
使用法:
クラス オブジェクトを作成します。通常は構築メソッド内で、またはメソッドを使用して作成します。このメソッドでは、対応する判定を追加するだけです。

単一モードと共有モードの違い:

すべてのクラスのインスタンスが固有になります。

しかし、単一状態モードの実装は次のとおりです:

クラス内、つまりコンストラクター メソッドまたは静的 getInstace メソッド内で、インスタンスが存在する場合は作成せずに直接返されます。

共有モード 実装方法は次のとおりです:

このインスタンスを使用するときは、まずこのハッシュテーブルにアクセスして取得します。get が空の場合は、インスタンスを生成し、クラスのインスタンスを人のハッシュテーブルに置きます。 get が空でない場合は、この例を直接使用します。

(2)

例 1:

public class Singleton {

public static Singleton getInstance() {

if (s == null)

s = new Singleton();

Return s;
}
}
// テストクラス
class singletonTest {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
if (s1==s2)
System.out.println("s1 は s2 と同じインスタンスです");
else
System.out.println("s1 は s2 と同じインスタンスではありません");
}
}

singletonTest の結果:
s1 は s2 と同じインスタンスです

(3)
例 2:
class Singleton {
static boolean instance_flag = false; // true if 1 インスタンス
public Singleton() {
if (instance_flag)
throw new SingletonException("許可され​​るインスタンスは 1 つだけ");
else
// 1 つのインスタンスにフラグを設定します
}
}

----------------------------- --- - Observerパターン(Observer) --------------------------------
(1)
基本概念:
オブザーバー パターンは動作パターンであり、その目的は、オブジェクト間の 1 対多の依存関係を定義することです。オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトが通知され、自動的に更新されます。

このパターンの主要なオブジェクトは、被験者と観察者です。ターゲットには、それに依存する任意の数のオブザーバーを含めることができます。ターゲットの状態が変化すると、すべてのオブザーバーがこの通知に応答して、その状態をターゲットのステータスと同期させるためにターゲットに問い合わせます。

適用可能なシナリオ:

オブザーバー モードは、1 対多の依存関係を持つオブジェクト間で使用されます。依存関係が変更されると、すべての依存関係に更新が通知されます。したがって、依存関係には依存関係を追加/削除するメソッドが必要であり、追加された依存関係はコンテナーに配置でき、依存関係に更新を通知するメソッドが必要です。

(2)
考察:
(1)
ターゲット(サブジェクト)とオブザーバー(オブザーバー)インターフェースを確立する:
ターゲット(サブジェクト)インターフェース:
オブザーバーオブジェクトを登録するためのインターフェースを確立する public voidattach(Observer o) ;
オブザーバー オブジェクトを削除するためのインターフェイスを確立します。 public void detach(Observer o);
ターゲットの状態が変化したときにオブザーバー オブジェクトに通知を発行するためのインターフェイスを確立します。 public void Notice();

observer(observer )Interface:
ターゲット通知を受信した後のインターフェースの更新: public void update();

(3)
例:
生徒は、適切なタイミングで更新できるように、教師の電話番号を知っている必要があります。このような組み合わせでは、教師は観察対象

(主体)となり、生徒は情報を知る必要がある観察者となり、教師の電話番号が変更されると生徒に通知され、対応する電話記録が更新されます

。記録。

具体的な例は次のとおりです:
サブジェクト コード:
public インターフェース Subject{
public voidattach(Observer o);
public void detach(Observer o);
public void Notice();
}

Observer コード:
public インターフェース Observer{
public void update();
}

Teacher code;
import java.util.Vector;
public class Teacher は Subject{
private String 電話;
private Vector students;
public Teacher(){
phone = "";
students = new Vector();
}
public voidattach(Observer o){
students.add(o);
}
public void detach(Observer o){
students.remove(o );
} L public void Notice () {
for (int i = 0; i & lt; students.size (); i ++)
(オブザーバー) ONE (ONE String Phone){
this.phone =電話;
Notice(); ‐‐‐ キー } ‐ }

Student代码:
publicクラス Student実装Observer{
private String name;
private String 電話;
private Teacher Teacher;
public Student(String name,Teacher t){
this.name = name;
Teacher = t;
}
public void show(){
System.out.println("Name:"+name+"nTeacher'sphone:"+phone);
}
public void update(){
Phone = Teacher.getPhone();
}
}
クライアント代码:
パッケージオブザーバー;
インポートjava.util.Vector;
パブリッククラスクライアント{ -->可以只定目監視者、観察者、另外的ベクトル、只了输入結果。
public static void main(String[] args){
Vector students = new Vector();
Teacher t = new Teacher();
for(int i= 0 ;i<10;i++){
Student st = new Student("lili "+i,t);
students.add(st);
t.attach(st);
}
t.setPhone("88803807");
for(int i=0;i<10;i++)
((学生)students.get(i)).show();
t.setPhone("88808880");
for(int i=0;i<10;i++)
((学生)students.get(i) )).show();
}
}

全体:Observer モードの最も有名な用途は MVC 構造であり、Observer モードは文書や図表プログラムの作成に非常に適しています。 ------------------------ 迭代器モード(イテレータ) ------------------ -------------

(1)

基本概念:
代器モードは実行型モードに属し、その意図は、一種類の方法顺序访问一結合オブジェクト内で各要素を取得します。このオブジェクトを公開する必要がある

内部表示。
は少なくとも、first、next、previous、last、isOver を通過するか、または特定の条件を満たす通過選択子を通過できます。

(2)

構造:
はインターフェースによって一实现类構成.
インターフェース:
主は各历遍を決定する方法.
实现类:
必要一计算点private int current=0 ; Bector、gector、来来存在原来的的的进行的一团东西; *
Item: つまり、集合内の各オブジェクトの種類。若は String、つまりすべての ITEM が String に変更され、若は他の独自の種類に変更されます。 --->重要です。  
*/
public item first();

public item next();

public boolean isDone();

public item currentItem();

}

Controller类实现了Iteratorインターフェイス。
package iterator;
import java. util.Vector;
public class コントローラーは Iterator を実装します{
private int current =0;

Vector channel;

public Controller(Vector v){
channel = v;
}
public item first(){
current = 0;
return (Item)channel.get(current);
}

public item next(){

current ++;
return (Item)channel.get(current);
}
public item currentItem(){
return (Item )channel.get(current);
}
public boolean isDone(){
return current>= channel.size()-1;
}
}

テレビ インターフェイス:
パッケージ イテレータ;
インポート java.util.Vector;
パブリック インターフェイス テレビ {
Public Iterator createIterator();
}
HaierTV クラスはテレビ インターフェイスを実装します。
パッケージ イテレータ;
import java.util.Vector;
public class HaierTVimples Television{ ---Object
private Vector channel;
public HaierTV(){
channel = new Vector();
channel.addElement(new item( "チャンネル 1")); -- 各要素は VECTOR に保存されます
channel.addElement(new Items("channel 2"));
channel.addElement(new Items("channel 3"));
channel.addElement( ( 新しいアイテム("チャンネル 4"));
channel.addElement(新しいアイテム("チャンネル 5"));
channel.addElement(" channel 7"));
}
public Iterator createIterator(){
return new Controller(channel); -- この VECTOR をイテレータのコンストラクターに入れます
}
}
Client:
package iterator;
public class Client{
public static void main(String[] args){
Television tv = new HaierTV();
Iterator it =tv.createIterator();
System.out.println(it.first().getName( ));
while(!it.isDone()){
System.out.println(it.next().getName());
}
}
}
Item クラス インターフェイス:
package public class Items{
private String name;
public item(String aName){
name = aName; ------------------- ファサード -------------- ------ ------
(1)
ファサード モードは、このサブシステムを使いやすくする高レベルのインターフェイスを定義する構造モードです。
外観モードの主な目的は、サブシステムの複雑な処理に便利な呼び出しメソッドを提供し、サブシステムを使いやすくすることです。
--->複雑なプロセスを組み込み、シンプルなアプリケーションインターフェースを提供します。

(2)
例えば、お茶を作るプロセスでは、水を沸騰させ、お茶を準備し、お茶を入れるという作業を行う必要があります。茶葉をキルトに入れ、熱湯を湯飲みに注ぎます。この工程を経て初めて美味しい茶葉が淹れられます。これは一般的に使用されるステップであり、お茶を作るステップの 80% は次のようになります。次の MakeACuppa() の例では、ファサード モードを使用するため、次のような場合に便利です。ステップメソッドを呼び出します。これは外観モードであり、内部の詳細はブロックされています。

パブリック クラス TeaCup{....}

パブリック クラス TeaBag{....}

パブリック クラス Water{....}

パブリック クラス FacadeCuppaMaker{
private boolean TeaBagIsSteeped;

public FacadeCuppaMaker () () {

System.out.println ("Facadecuppamaker はお茶を急ぐ準備ができています");

水 Water = new Water();

cup.addFacadeTeaBag(teaBag);

Water.boilFacadeWater() ;

cup.addFacadeWater(水);

cup.steepTeaBag();

---- ------------------------ アダプターモード (アダプター) ------------------ ------------------------

(1)

アダプター パターンの目的は、既存のアダプター パターンを再利用することです。クラス/インターフェイスを作成し、顧客が必要とする別のクラス/インターフェイスに変換/具体化します。

(2)

インスタンスの再利用方法:
再利用したいクラスを対象クラスの構築メソッドに入れてインスタンス化し、対象クラスの対応するメソッド内で呼び出して元のメソッドを変更します

のパラメーター、または対応するロジックを追加します。つまり、既存のクラスの元のメソッドが再利用されます。

再利用するクラス:
public class Adaptee{
public long getPower(longbase,long exp){
long result=1;
for(int i=0;i result*=base;
結果を返します。
パブリック インターフェイス Target{
public long get2Power(long exp);

}


public クラス アダプターは Target{
private Adaptee pt;
public Adapter(){

pt = new Adaptee();

}
public long get2Power( long exp) {x Return pt.getpower (2, exp); --- 元のメソッドのパラメータを変更します
}}

(3)



l l l l l :
public boolean updateRecordStates(Double RecordId, Double tableNameMapping,int state,boolean

subRecordUpdate) は RemoteException をスローします。 tableNameMapping,state,subRecordUpdate);
}

アダプター モードが使用されている場合:
インターフェイス:
public boolean updateStatesAdapterForSelfPanel(Double RecordId,Double tableNameMapping, int state)

throws RemoteException;
implementation Class:
public boolean updateStatesAdapterForSelfPanel(Double RecordI) d ,Double tableNameMapping,int state)

throws RemoteException

{
return this.updateRecordStates(recordId,tableNameMapping,state,false);
}

--------- ------------- ------------ プロキシモード (Proxy) ------------------------ -------
( 1)
プロキシの利点:

---> オブジェクトに間接的にアクセスする際に、その前後に他のロジック コードを追加できます。

--->はい、元のロジックに他のロジックが追加され、最終的に新しいロジックが生成されます。

(2)
静的プロキシ:

--> 元のクラスとエージェント クラスは 1 対 1 に対応する必要があります。

--> どちらも共通のインターフェイスを実装するか、同じ抽象クラスを継承します。
--> プロキシ クラスで元のクラスをインスタンス化し、元のクラス メソッドの前後に新しいロジックを追加するだけです。象 以下: 角 抽象文字:
abstract Public Class Subject
{
Abstract Public Void Request (); Public void request () {

system.out. role:

public class ProxySubject extends Subject

{
private RealSubject realSubject //実際のロールをプロキシ ロールの属性として使用します

public ProxySubject()
{ realSubject=new RealSubject() }

public void request; () // 元のメソッド名と同じ{ postRequest();
}

private void preRequest()


}

クライアント呼び出し:
Subject sub=new ProxySubject();
Sub.request();

(3)

動的プロキシ クラス

Java 動的プロキシ クラスは Java.lang.reflect パッケージの下にあり、通常は次の 2 つのクラスが含まれます:
1)

Interface InvocationHandler: このインターフェイスではメソッドが 1 つだけ定義されています: invoke(Object obj 、メソッドメソッド、Object[] args)


。実際の使用では、通常、最初のパラメータ obj はプロキシ クラスを指し、method はプロキシ メソッド、args はメソッドのパラメータ配列を指します。この抽象メソッド

は、プロキシ クラスに動的に実装されます。
2)

Proxy: このクラスは動的プロキシ クラスであり、主に次の内容が含まれます:

Static Object newProxyInstance(ClassLoader loader, Class[] Interfaces, InvocationHandler h): プロキシ クラスを返します

のインスタンス、返されたプロキシ クラスはプロキシ クラスとして使用できます。
いわゆるダイナミック プロキシはクラスです。これは実行時に生成されるクラスであり、生成するときにそれに一連のインターフェイスを提供する必要があります。その後、クラスはこれらのインターフェイスを実装することを宣言します。

3)

動的プロキシクラスを使用する場合、InvocationHandlerインターフェース、
publicインターフェースSubject
{
public void request();
}

特定のロールRealSubject: 上記と同じ。 java.lang .reflect.Method;

import java.lang.reflect.InvocationHandler;

public class DynamicSubject は InvocationHandler を実装します {

private Object sub;

public DynamicSubject(Object obj) {
sub = obj;
}

public Object invoke (オブジェクト プロキシ 、メソッド メソッド、Object[] args) throws Throwable {
System.out.println("before call " + メソッド);

Method.invoke(sub,args);

System.out.println(" " + メソッド);
Return null;

}

}

==>
method.invoke(sub,args);
実際には、プロキシオブジェクトの実行するメソッドを呼び出すことになり、メソッド パラメータ sub は実際のプロキシ オブジェクトであり、args はプロキシ オブジェクトの対応する操作を実行するために必要なパラメータです。動的プロキシ クラスを通じて、呼び出しの前後にいくつかの関連操作を実行できます。

クライアント:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

public class Client

{
static public void main(String[] args) throws Throwable
{
RealSubject rs = new RealSubject(); //ここにプロキシ クラスを指定します
InvocationHandler ds = new DynamicSubject(rs) //プロキシ クラスを初期化します

Subject subject = (Subject) Proxy.newProxyInstance(rs.getClass().getClassLoader(),rs.getClass


().getInterfaces(),ds );
subject.request();
}

5)
インスタンス 2 :

package DynamicProxy;

public インターフェース Work {
public void startWork();
}

package DynamicProxy;
public class JasonWork 実装 Work {
public void startWork() {
System.out.println("jason start to work ...");
}
}

パブリック インターフェイス Play {
public void startPlay();
}

public class JasonPlay 実装 Play {
public void startPlay() {

System.out.println("jason start再生するには ... "); amicproxy = New DynamicProxy (Work) ;

Work jasonproxy=(Work)Proxy.newProxyInstance(work.getClass().getClassLoader(),

work.getClass().getInterfaces(), DynamicProxy ); JasonPlay play=new JasonPlay();

InvocationHandler DynamicProxy=new DynamicProxy(play);

Play jasonproxy=(Play)Proxy.newProxyInstance(play.getClass().getClassLoader(),

play.getClass().getInterfaces (),dynamicProxy);
Jasonproxy.startPlay();
}

}

===>動的プロキシ クラスは、任意の種類の実際のクラス (作業/再生) と組み合わせて、動的プロキシを実行できます。





----------------------------- ステートモード(状態) ----------- ---- ----------------

(1)

状態モードの定義:
異なる状態、異なる動作。つまり、各状態には対応する動作があります。 :
State モードは実際に使用する場合の方が一般的であり、状態の切り替えに If elseif else を使用することが多いため、このような状態の判断切り替えが繰り返し発生する場合は、State モードが使用できるかどうかを検討する必要があります。

-->周期的に変化し続ける内部状態に適しています。

(2)
状態は、オブジェクト + オブジェクト内のプロパティ (プロパティ インターフェイス + 特定のプロパティ) の 2 つの部分で構成されます。
オブジェクトには次の要素が必要です。そのプロパティ、およびそのセッターとゲッターを設定し、その初期状態と表示状態を呼び出すメソッドを設定します (状態が独自の表示メソッドを呼び出す)

プロパティ インターフェイスには、特定のプロパティが必要です。オブジェクトが入力されると、実装メソッドで、次に表示されるオブジェクトの属性が設定される必要があります --> そうすると、次回オブジェクトがメソッドを呼び出すときにその属性値が変更されます。

ステート モードとオブザーバー モードの違い:

ステート モードは、オブザーバー モードと同様、1 対多のモードです。ただし、オブザーバー モードでは、「1 つ」が変更されると、すべての「多数」も更新されます。

状態モードは、「多数」が「1 つ」の状態であり、「1 つ」の状態が連続サイクルにあることを強調します。

1 と多の間の関係を確立する方法:

「多」はすべてインターフェイスを実装します。したがって、「one」のクラスでは「many」のインターフェースが宣言されており、「many」内の「one」との関係を確立したい場合は、クラス内で「one」を直接宣言するだけで済みます。

(3)
コード:
publicインターフェースColor {
public void show();

}

package state;

class Light
{
Color color;
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}

public Light()
{
color=new RedColor(this);
}

public void showColor()
{
color.show();
}

}

class RedColor は Color
{
Light light;
public RedColor(Light light)
{
this.light=light;
}

public void show() を実装します。
{
System.out.println("色は赤です、車は停止しなければなりません!");
System.out.println("この状態でこれを実行する必要があるすべてのロジックを書き留めてください....");
light.setColor(new GreenColor(light));
}
}

class GreenColor は Color
{
Light light;
public GreenColor(Light light)
{
this.light=light;
}

public void show ()
{
System.out.println("色は緑です、車は走れます!");
System.out.println("この状態でこれを行う必要があるすべてのロジックを書き留めてください...") ;
light.setColor(new YellowColor(light));
}
}

class YellowColor は Color
{
Light light;
public YellowColor(Light light)
{
this.light=light;
}

public void を実装しますshow()
{
System.out.println("色は黄色です、車は停止する必要があります!");
System.out.println("この状態でこれを実行する必要があるすべてのロジックを書き留めてください.... " );
light.setColor(new RedColor(light));
}
}

public class CarLight {
public static void main(String[] args) {
Light light=new Light();

//最初の呼び出しは red light
light.showColor();
//その後、green light と呼ばれます
light.showColor();
//それは yellow light と呼ばれます
light.showColor();
//継続的に呼び出し、
}
}

---------------------------- フライウェイトモード (Flyweight) - -----------------------------
(1)
主にオブジェクト作成時に共有技術を使用してメモリを削減するために使用されますオブジェクトの使用法。プログラムの効率とパフォーマンスを向上させるモードでは、プログラムの動作が大幅に高速化されます。つまり、システム内に同一のオブジェクトが 1 つだけ共有されます。それぞれがオブジェクトをインスタンス化する必要はありません。

ファクトリーモードはフライウェイトモードによく登場します。 Flyweight の内部状態は共有用であり、Flyweight ファクトリは内部状態オブジェクトを保存するオブジェクト ストレージ プール (Flyweight Pool) を維持する責任があります。

Flyweight の重要なアイデアは次のとおりです:

新しいオブジェクトを作成するとき:

まずハッシュテーブルから取得します --> 取得したオブジェクトが空かどうかを判断します --> 空の場合は、このオブジェクトを作成して元に戻しますハッシュテーブルに --> 存在する場合は、元の

オブジェクトを共有します。


(2)
インスタンス: (静的ファクトリー モードと比較)

public インターフェイス Car {

public void showCarName();

}

class BMWCar 実装 Car
{

public void showCarName()

{

System.out.println("this is the BMWCar .");

}
}

class FordCar 実装 Car
{
public void showCarName()
{

System.out.println ("これは FordCar です。");

}
}

class CarFactory
{
public static Car car;
public static Car getCar(String name)

{

if("BMW".等しい(名前))
{
車 = 新しい BMWCar();
}
if("フォード".equals(名前))
{
車 = 新しいフォードカー();
}
車を返す;
}
}

class CarFlyWeightFactory
{
public Car car;
private Hashtable carPool=new Hashtable();
public Car getCar(String name)
{
if("BMW".equals(name))
{
car=carPool.get(name);
if(car ==null)
{
car=new BMWCar();
carPool.put(name, car);
}
}

if("Ford".equals(name))
{
car=carPool.get( name);
if(car==null)
{
car=new FordCar();
carPool.put(name, car);
}
}
return car;
}
public int getNumber(){ return carPool .getSize(); }
}


public class Test {

public static void main(String[] args) {
CarFlyWeightFactory carFlyWeightFactory=new CarFlyWeightFactory();
Car carf1=carFlyWeightFactory.getCar("Ford");
carf1.showCarName( );
Car carf2=carFlyWeightFactory.getCar("Ford");
carf2.showCarName();
if(carf1==carf2)
{
System.out.println("同一部车来的");
}
else
{
System.out.println("異なる一部车来的");
}
System.out.println("车の数は:"+carFlyWeightFactory.getNumber());
}
}

出:
これはフォードカーです。
これはフォードカーです。
同一部车来的

----------------------职责链モード(責任の連鎖) ------------------------
(1)
責任の連鎖职责链モード:
回避要求の送信者と受信者これらのオブジェクトを 1 つのストリップにまとめ、いずれかのオブジェクトが処理を完了するまでリクエストを転送します。チェーン送信リクエストに沿って、受信者が安全な形式であることを保護し、各チェーン上のオブジェクトはすべて、一致する処理リクエストとログイン上の後続者のインターフェイスを持ちます (つまり、次の例では、自分のメソッドで再度同じものを使用します)

(2)

public class Boy {


private boolean hasCar; // 有無有车
private boolean hasHouse; // 否か有房
private boolean hasResponsibility; // 否か有责任心

public Boy() {

}


public Boy(boolean hasCar, boolean hasHouse, boolean hasResponsibility) {

this.hasCar = hasCar;

this.hasHouse = hasHouse;
this.hasResponsibility = hasResponsibility ;

public void setHasHouse(boolean hasHouse) {
this.hasHouse = hasHouse;

}


public boolean isHasResponsibility() {
return hasResponsibility;

}


public void setHasResponsibility(boolean hasResponsibility) {
this.hasResponsibility = 責任があります;

}

}

パブリックインターフェイスHandler {

public void handleRequest(Boyboy);

}

public class HouseHandlerimplements Handler {

private Handler handler;

public HouseHandler(Handler handler) {

this.handler = handler;
}

public Handler getHandler() {

return handler;

}

public void setHandler(Handler handler) {

this.handler = handler;

}

public void handleRequest(Boyboy) {

if ( boy.isHasHouse()) {

System.out.println("没想到吧,我还有房子");

} else {

System.out.println("我也没有房");
handler.handleRequest( boy);

}

}
}

public class CarHandler 実装 Handler {


private Handler handler;

public CarHandler(Handler handler) {

this.handler = handler;
}

public Handler getHandler() {
return handler;
}

public void setHandler(Handler handler) {
this.handler = handler;

}

public void handleRequest(Boyboy) {
if (boy.isHasCar()) {
System.out.println("はは、私は車を持っています");
} else {
System.out.println("私は車を持っています車を持っていない" 車");
handler.handleRequest(boy);
}
}
}

public class ResponsibilityHandler 実装 Handler {

private Handler handler;

public ResponsibilityHandler(Handler handler) {
this. handler = handler;
}

public Handler getHandler() {
return handler;
}

public void setHandler(Handler handler) {
this.handler = handler;
}

public void handleRequest(Boyboy) {
if (boy.isHasResponsibility( )) {
System.out.println("責任感しかない");
} else {
System.out.println("責任感がない");
handler.handleRequest (男の子);
}
}
}

public class Girl {

public static void main(String[] args) {
// この男の子には車も家もありませんが、非常に責任感があります
Boy boy = new Boy(false, false, true);
// setHanlder メソッドも使用できます
Handler handler = new CarHandler(new HouseHandler(
ResponsibilityHandler(null)));

リクエストの方法受け入れ側オブジェクト間でチェーンを渡します。最初の受け入れ側オブジェクトで受け入れられない場合は、2 番目のオブジェクトに渡されません:
1 .Each specific受信側オブジェクトは次の構築メソッドを採用します:

public CarHandler(Handler handler) { this.handler = handler; }

2. 呼び出されたとき、それが受け入れられた場合、各受信側オブジェクトはメソッド handleRequest() を実装します。 true のコンテンツが実行され、受け入れられない場合は false のコンテンツが実行され、handleRequest() メソッドが引き続き呼び出されます。
3. 特定のハンドラーを生成するときに、マルチレイヤーを使用します。このように、前のレイヤーの car のメソッドを呼び出した後、対応する house のメソッドが呼び出され、最後に ResponsibilityHandler のメソッドが呼び出されます

==> 最初の 2 つのハンドラーは、この構造を使用します。パラメーターを含むメソッドと最後のメソッドは、NULL 構築メソッドを使用します

--------------------------------- Memento ---- -----------------------------

(1)

メモモードは行動モードであり、その意図はオブジェクトを破壊せずにカプセル化を実現するには、オブジェクトの内部状態をキャプチャし、この状態をオブジェクトの外部に保存します。これにより、オブジェクトを後で元の保存された状態に復元できます。


(2)
例は次のとおりです:
属性に加えて、状態を保存および復元するメソッドも必要です。

従業員のステータスを記録するために使用されるオブジェクトMementoがあります。

CareTaker は、Memento を保存して戻すメソッドが必要です -> ポインターとコンテナーが必要です:

package memento;
public class Memento{
    String name;
    int age;
    public Memento(String name,int age){
       this.name = name;
       this.age = age;
    }
}
ログイン後にコピー

CareTaker コード:

package memento;
public class Employee{
    private String name;
    private int age;
    public Employee(String aName,int aAge){
       name = aName;
       age = aAge;
    }
    public void setName(String aName){
       name = aName;
    }
    public void setAge(int aAge){
       age = aAge;
    }
    public Memento  saveMemento(){
       return new Memento(name,age);
    }
    public void restoreMemento(Memento memento){
       age = memento.age;
       name = memento.name;
    }
    public int getAge(){
       return age;
    }
    public String getName(){
       return name;
    }
}
ログイン後にコピー

クライアントコード:

package memento;
import java.util.Vector;
public class CareTaker{
    private Vector v;
    private int  current;
    public CareTaker(){
       current = -1;
       v = new Vector();
    }
    public void setMemento(Memento mem){
       current ++;
       v.add(mem);
    }
    public Memento getMemento(){
       if(current>0){
           current --;
           return(Memento) v.get(current);
       }
       return null;
    }
}
ログイン後にコピー

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート