忘れられたデザインパターン-空のオブジェクトパターン(再現)

著作権表示:この記事はブロガーの元の記事であり、CC 4.0 BY-SAの著作権表示に従います。転載するには、元のソースへのリンクとこの文を添付してください。
この記事へのリンク:https://blog.csdn.net/qiumengchen12/article/details/44923139

パターン名

特定のタイプのオブジェクトがない場合の代理としてオブジェクトを提供します。Null Objectは、インテリジェントな何もしない動作を提供し、共同作業者から詳細を隠します。

問題

実際のアプリケーションシナリオがないデザインパターンは、不正を実行しています。デザインパターンを学ぶことは、その本質を理解するだけでなく、実際のデザインに適用して適応することでもあります。以下を見てみましょう。このヌルオブジェクトパターンはどのような状況で役立ちますか?

このようなシナリオを想定します。
書籍情報クエリシステムで、メソッドを呼び出し、検索する書籍のIDを渡すと、検索する書籍オブジェクトが返されるため、次のメソッドを呼び出すことができます。本に関する情報を出力するオブジェクト。

このようなシーンはプログラミングではかなり一般的だと思います。次に、次の特定のコードを実装しましょう。
まず、ConcreteBookクラスのコードを見てみましょう(本の情報を表示するためのコンストラクターとshow()メソッドを提供します)。

public class ConcreteBook {
    
    
    private int ID;
    private String name;
    private String author;

    // 构造函数
    public ConcreteBook(int ID, String name, String author) {
    
    
        this.ID = ID;
        this.name = name;
        this.author = author;
    }

    /**
     * 
     * Description About show: <br>
     * 展示图书的相关信息
     * 
     * @version V1.0
     */
    public void show() {
    
    
        System.out.println(ID + "**" + name + "**" + author);
    }
}

ブックオブジェクトを作成するブックファクトリのコードを見てみましょう(主にConcreteeBookを取得するメソッドを提供します)。

public class BookFactory {
    
    
    /**
     * 
     * Description About getBook: <br>
     * 根据ConcreteBook的ID,获取图书对象。
     * @param ID 图书的ID
     * @return 图书对象
     * @version V1.0
     */

    public ConcreteBook getBook(int ID) {
    
    
        ConcreteBook book = null;
        switch (ID) {
    
    
        case 1:
            book = new ConcreteBook(ID, "设计模式", "GoF");
            break;
        case 2:
            book = new ConcreteBook(ID, "被遗忘的设计模式", "Null Object Pattern");
            break;
        default:
            book = null;// 其实这个可以省略,因为初始化已经赋值为null。
            break;
        }

        return book;
    }
}

最後に、クライアントコードを見てください。

public class Client {
    
    

    static void main(String[] args) {
    
    
        BookFactory bookFactory = new BookFactory();
        ConcreteBook book = bookFactory.getBook(1);
        book.show();
    }
}

上記の3つのコードは非常に単純なので、詳細には説明しません。次に、実行してみましょう。結果は次のとおりです。
ここに画像の説明を挿入します
非常に良好で、スムーズに実行されます。この時点で、ConcreteBook book = bookFactory.getBook(1);の1を2に変更すると、正常に実行されます。今回は-1に変更しました。もう一度実行して
ここに画像の説明を挿入します
みると、次のエラーが見つかりました。Nullポインタエラー、はい、これはJava初心者によって報告される最も一般的なエラーであるはずです。book.show()が28行目にエラーを報告したことを示します。どうしてこれなの?bookFactory.getBook()メソッドを介してConcreteeBookオブジェクトを取得するときに、渡すパラメーター、つまり本のIDが不正な値(-1など)であるか、存在しない(3など)場合、 )(実際、この状況はしばしば発生します。)、nullを返し、探している本の情報が存在しないことを示します。このとき、bookはnullです。book.show()を再度呼び出します。もちろん、nullポインタエラーを報告する必要があります。それを解決する方法は?

私たちのより一般的なアプローチは、クライアントに判断を追加して、それがnullかどうかを判断することです。nullの場合、show()メソッドは呼び出されなくなります。nullでない場合は、show()メソッドを呼び出します。変更点は次のとおりです。

public static void main(String[] args) {
    
    
        BookFactory bookFactory = new BookFactory();
        ConcreteBook book = bookFactory.getBook(-1);
        //判断book对象是否为null。
        if (book == null) {
    
    
            System.out.println("book对象为 null。");
        } else {
    
    
            book.show();
        }
}

この時点で再度実行しても、エラーは報告されません。代わりに、次のように出力されます。bookオブジェクトはnullです。

しかし、あなたはそれを考慮しましたか?これはエラーを排除しますが、それは本当に良いですか?プログラム内にgetBook()メソッドを呼び出す場所が多い場合や、クライアントが多い場合(たとえば、ライブラリに複数のクエリ端末が必要)、bookオブジェクトかどうかを判断する必要はないと思います。多くの場所でnullですか?これは悪いことではありません。一箇所に判断がなく、エラーが報告された場合、プログラムは実行を継続できないか、クラッシュする可能性があります。また、クライアントを過度に信頼したり、クライアント上のプログラム全体の安定性を信頼したりしないことを覚えておく必要があります。また、上記の処理方法のように、取得したオブジェクトがnullの場合、出力プロンプト情報はクライアントによってカスタマイズされますが、これはシステム自体ではなくクライアントに主導権を与えませんか?

解決

まず、NullオブジェクトパターンのUMLクラス図構造を見てみましょう。
ここに画像の説明を挿入します
このクラス図構造は実際には非常に単純です。内部のRealObjectは実際にはConcreteBookクラスと同等であり、NullObjectは追加する空のオブジェクトクラスです。 AbstractObjectクラスは、提案する親クラスです。ClientとAbstractObjectの間にBookFactoryを追加しました。

次に、コードを変更しましょう。
新しく追加された抽象インターフェースBookクラスのコード

interface Book {
    
    
    // 判断Book对象是否为空对象(Null Object)
    public boolean isNull();

    // 展示Book对象的信息内容。
    public void show();
}

新しく追加されたnullオブジェクトクラスNullBookクラス(Bookクラスから継承)のコード:

public class NullBook implements Book {
    
    
    public boolean isNull() {
    
    
        return true;
    }

    public void show() {
    
    

    }
}

元のConcreteBookクラスの変更されたコード(Bookインターフェイスの実現を追加し、isNullメソッドを実装します):

public class ConcreteBook implements Book{
    
    
    private int ID;
    private String name;
    private String author;

    // 构造函数
    public ConcreteBook(int ID, String name, String author) {
    
    
        this.ID = ID;
        this.name = name;
        this.author = author;
    }

    /**
     * 
     * Description About show: <br>
     * 展示图书的相关信息
     * 
     * @version V1.0
     */
    public void show() {
    
    
        System.out.println(ID + "**" + name + "**" + author);
    }
    public boolean isNull(){
    
    
        return false;
    }
}

ファクトリクラス(BookFactory)の変更されたコード(戻りオブジェクトはConcreteeBookからBookに変更され、IDが不正な値であるか存在しない場合、NullBookオブジェクトを返します。):

public class BookFactory {
    
    
    /**
     * Description About getBook: <br>
     * 根据ConcreteBook的ID,获取图书对象。
     * @param ID 图书的ID
     * @return 图书对象
     * @version V1.0
     */

    public Book getBook(int ID) {
    
    
        Book book;//将原来的ConcreteBook改为Book
        switch (ID) {
    
    
        case 1:
            book = new ConcreteBook(ID, "设计模式", "GoF");
            break;
        case 2:
            book = new ConcreteBook(ID, "被遗忘的设计模式", "Null Object Pattern");
            break;
        default:
            book = new NullBook();//创建一个NullBook对象
            break;
        }

        return book;
    }

クライアントコードは次のとおりです。

public static void main(String[] args) {
    
    
        BookFactory bookFactory = new BookFactory();
        Book book = bookFactory.getBook(-1);
        book.show();
    }

実行後、渡されたパラメータが不正な値または存在しない値であっても、エラーが報告されないことがわかりました。これは、Nullオブジェクトパターンの最初の利点です。しかし、今ではエラーレポートも出力もありません。それは間違いなく十分に友好的ではなく、十分に人道的でもありません。この時点で、NullBookクラスのshowメソッドで、出力リマインダーをカスタマイズできます。ユーザーが空のオブジェクトのshowメソッドを呼び出すと、カスタマイズされたリマインダーが出力されます。今回は、どこでも1つのカスタマイズと出力を実現できます。イニシアチブは、クライアントの手ではなく、私たちの手に委ねられています。これは、Null ObjectPatternの2番目の利点です。

たとえば、変更されたNullBookクラスコードに次の変更を加えます。

public class NullBook implements Book {
    
    
    public boolean isNull() {
    
    
        return true;
    }

    public void show() {
    
    
        System.out.println("Sorry,未找到符合您输入的ID的图书信息,请确认您输入的不是非法值。");
    }
}

この時点で、クライアントを実行すると、コンソールの出力は次のようになります。申し訳ありません。入力したIDに一致する書籍情報が見つかりません。入力した値が不正な値でないことを確認してください。

実際、クライアント側でテストせずにプログラムがエラーを報告しないようにすることはできますが、次のように、対応するテストを実行するのが最善の方法です。

public static void main(String[] args) {
    
    
        BookFactory bookFactory = new BookFactory();
        Book book = bookFactory.getBook(-1);
        if (book.isNull()) {
    
    
            //这里由客户端定制提醒代码
            System.out.println("兄弟,你输入的ID不符合规范吧。");
        }else{
    
    
            book.show();
        }
    }

比較すると、book.isNull()はbook == nullよりも少しエレガントであることがわかります。この時点で、Null ObjectPatternの導入はおそらく終了しています。Null Object Patternは実際には少し興味深いものであり、システム全体をより堅牢にしていると言えます。

結果

ヌルオブジェクトパターンは、忘れられたデザインパターンとして、忘れられない効果があります。

(1)システムの安定性を強化し、システム全体へのnullポインタエラーの影響を効果的に防止し、システムをより安定させることができます。

(2)空のオブジェクトの状況のカスタマイズされた制御を実現し、空のオブジェクトを処理するイニシアチブを習得できます。

(3)システム全体の安定した運用を保証するためにクライアントに依存しません。

(4)== nullをisNullに置き換えると、よりエレガントで理解しやすくなります。

おすすめ

転載: blog.csdn.net/qq_34365173/article/details/108560495