大規模なJavaの高度なトピック(C)ソフトウェアアーキテクチャの設計原則(下)

序文

今日の話題を始める第二の教訓は、ソフトウェアアーキテクチャの設計原理を共有し続けるために次の章では、導入されます。インターフェイス分離原則、デメテルの原則、リヒターの置換原則と合成多重化の原則を。最初の章ではこの章の参考図書「春5コア原則」春内臓ハート(その本質と組み合わせて何の電子ギアは、私自身の理解、単語の手のそれらをノックアウトする言葉ではありません)。

インターフェイスの棲み分け原理

界面分離原理(インターフェース偏析Principke、ISP)がそれに依存してはならないクライアントは、インタフェースはなく、単一の一般的なを使用することなく、専用のインターフェース、複数のインタフェースの使用を指します。私たちは、インタフェースを設計する際に、この原理は次のことに注意する必要があることを知っています:

インターフェースの別のクラスに依存して(1)クラスが最小に基づくべきです。

(2)は、単一のインターフェイスを確立、肥大化したインターフェースを作成しないでください。

インターフェースを最小限に抑えることができる改良プロセスインタフェース(3)(良くない、適切でなければなりません)。

私たちはしばしば高い凝集と低カップリング設計を言うに沿って分離原則インタフェース、クラスが良い読みやすさ、拡張性と保守性を持つことができます。私たちは、将来性の変化の可能性は、いくつかの事前の判断を行うために場所を含めたビジネスモデルを検討するために、時間を費やし、時間のインターフェースの設計について考える必要があります。だから、抽象的なため、ビジネスモデルを理解することは非常に重要です。

ここでは、コードの一部、抽象的な記述に動物の行動を見てください。

//描述动物行为的接口
public interface IAnimal {
    void eat();
    void fly();
    void swim();
}
//鸟类
public class Bird implements IAnimal {
    public void eat() {
    }

    public void fly() {
    }

    public void swim() {
    }
}
//狗
public class Dog implements IAnimal {
    public void eat() {
    }

    public void fly() {
    }

    public void swim() {
    }
}

図から分かるように、スイムBRID()メソッドは、空にすることができ、及び犬フライ()メソッドは明らかに不可能です。この時点で、我々は異なるインタフェースを設計するためにさまざまな動物の行動に焦点を当てたが、コードを見て、IEatAnimal、IFlyAnimalとISwimAnimalインターフェースを設計しました:

public interface IEatAnimal {
    void eat();
}
public interface IFlyAnimal {
    void fly();
}
public interface ISwimAnimal {
    void swim();
}

この時点で、唯一の明確させ、IEatAnimal犬とISwimAnimalインタフェースが可能実装する必要があります。

public class Dog implements IEatAnimal,ISwimAnimal {

    public void eat() {
    }

    public void swim() {
    }
}

ドミトリー原則

ディミトリス原理(デメテルのLoDの法則)は、クラスとクラスの間の結合の程度を最小限に抑えるために、また、少なくとも既知の原則(最小知識の原則、LKP)として知られている他のオブジェクトの最小の理解に維持されるべき物体を指します。ディミトリス重点原理:、唯一の友達と通信するために、見知らぬ人に話をしません。メンバ変数は、プロセスの入力および出力パラメータに表示されますが、クラスの友人のカテゴリに属していないメソッド本体から今の内側、クラスの友人のクラスのメンバーと呼ぶことができます。

今すぐアクセス権システムを設計、ボスはラインを解放するコース数を確認する必要があります。このとき、ボスTeamLeaderは、統計、TeamLeader統計結果を検索し、ボス、コードを見てみましょうを伝えるために:

//课程类
public class Course {
}
//TeamLeader类
public class TeamLeader {
    public void checkNumberOfCourses(List<Course> courses){
        System.out.println("目前已经发布的课程数量:"+courses.size());
    }
}
//Boss类
public class Boss {
    public void commandCheckNumber(TeamLeader teamLeader){
        //模拟BOSS一页一页往下翻页,TeamLeader实时统计
        List<Course> courseList = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courseList.add(new Course());
        }
        teamLeader.checkNumberOfCourses(courseList);
    }
}
//调用方代码
public static void main(String[] args) {
        Boss boss = new Boss();
        TeamLeader teamLeader = new TeamLeader();
        boss.commandCheckNumber(teamLeader);
}

私はあなたへの書き込み、実際には、機能が達成された、コードは問題はないように見えますが、デメテルの原則に従って、ボスはちょうどコースと直接通信する必要はありませんが、結果が欲しいです。TeamLeader統計は、コースのオブジェクトを参照する必要があります。ボスとコースは友人ではなく、以下のクラス図から見ることができます。

変換するために、次のコード:

//TeamLeader做与course的交流
public class TeamLeader {
    public void checkNumberOfCourses(){
        List<Course> courses = new ArrayList<Course>();
        for (int i = 0; i < 20; i++) {
            courses.add(new Course());
        }
        System.out.println("目前已经发布的课程数量:"+courses.size());
    }
}
//Boss直接与TeamLeader交流,不再直接与Course交流
public class Boss {
    public void commandCheckNumber(TeamLeader teamLeader){
        //模拟BOSS一页一页往下翻页,TeamLeader实时统计
        teamLeader.checkNumberOfCourses();
    }
}

クラス図を見て、ボスはコースとは接触しませんでした

ここで念頭に置いてクマは、ソフトウェアの設計ルールを学習し、複雑なビジネスシナリオに遭遇、我々は状況に応じて行動する必要がある、強迫性障害を形成しません。

リヒター置換原則

リヒター置換原理(リスコフ置換Priciple、LSP)オブジェクトO1 T1の種類ごとに、T2は、オブジェクトの種類である場合には、O2 P T1定義されたすべてのプログラムが全てで置換されているように、O1、O2オブジェクトことを意味、プログラムPの挙動は、その後、型がタイプT2 T1のサブタイプである、変化していません。

この定義は、我々は再び理解し、それに持っている、非常に抽象的と思われます。ソフトウェアエンティティとして理解することができ、親クラスに適用された場合、それはそのサブクラスを適用する必要があり、参照は、親クラスがサブクラスのオブジェクトは、親オブジェクトに置き換えることができ、サブクラス、オブジェクトの使用に透明でなければならない場所、プログラムロジックではありません変更は、このような理解によると、意味の拡張:サブクラスは親クラスの機能を拡張することができますが、元の関数の親クラスを変更することはできません。

(1)サブクラスは抽象親クラスを実装することができるが、非抽象親クラスをカバーすることができません。

(2)サブクラスは、独自の方法を増大させることができます。

前提条件オーバーロードされた親クラスのサブクラスでは、この方法は(即ち、入力方法、参照)親クラスよりメソッドの入力パラメータがより緩和される(3)。

(4)場合、親クラスの実装サブクラス(リライトまたはリロードが抽象メソッドを実装する)、プロセスの事後条件(すなわち、メソッドの出力、戻り値)または親より厳しい親同じカテゴリ。

使用リヒター置換原理は次のような利点があります。

(1)の制約は、それが開閉の原理を反映して、フラッディングを継承しました。

ロバストネス(2)同僚の変化は非常に良好な相溶性を行うことができたときに、プログラムを強化し、プログラムの保守性とスケーラビリティを向上させ、需要になると導入のリスクを軽減します。

今正方形は特殊な長方形であることを、古典的なビジネスシナリオを記述するために、正方形、長方形や四角説明リヒター置換原則との関係、私たちは皆知っている、あなたは親クラスのRectangleを作成することができるように:

//矩形类
public class Rectangle {
    private long hight;
    private long width;

    public long getHight() {
        return hight;
    }

    public void setHight(long hight) {
        this.hight = hight;
    }

    public long getWidth() {
        return width;
    }

    public void setWidth(long width) {
        this.width = width;
    }
}
//正方形类
public class Square extends Rectangle {
    private long length;

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    @Override
    public long getHight() {
        return super.getHight();
    }

    @Override
    public void setHight(long hight) {
        super.setHight(hight);
    }

    @Override
    public long getWidth() {
        return super.getWidth();
    }

    @Override
    public void setWidth(long width) {
        super.setWidth(width);
    }
}
public class DemoTest {
    //在测试类中创建resize方法,长方形的宽应该大于等于高,我们让高一直增加,直至高等于宽,变成正方形。
    public static void resize(Rectangle rectangle) {
        while (rectangle.getWidth() >= rectangle.getHight()){
            rectangle.setHight(rectangle.getHight()+1);
            System.out.println("宽度:"+rectangle.getWidth()+"高度:"+rectangle.getHight());
        }
        System.out.println("resize方法结束!");
    }

    //测试代码如下
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        rectangle.setHight(10);
        rectangle.setWidth(20);
        resize(rectangle);
    }

コンソール出力を見て、最終的には幅よりも高さの大きいを発見した。このような状況が正方形の場合には正常であり、今、私たちはサブクラスにRectangleクラスを置き換える、それは論理的であり、リヒターの交換の原則に反していないだろう、サブクラスに親クラスを交換した後の期待を満たしていないプログラムの結果。したがって、私たちのコード設計の一定のリスクがあります。リヒターの置換原則は、親と子クラス、継承の制約の洪水の間に存在します。私たちは、正方形や長方形の四角形インターフェイス四角形に基づいて、共通の抽象インタフェースを作成してみましょう:

public interface Quadrangle { 
    long getWidth(); 
    long getHeight(); 
}

クラス長方形の矩形を変更します。

public class Rectangle implements Quadrangle {
    private long height;
    private long width;

    public long getHeight() {
        return height;
    }

    public long getWidth() {
        return width;
    }

    public void setHeight(long height) {
        this.height = height;
    }

    public void setWidth(long width) {
        this.width = width;
    }
}

正方形のクラススクエアカテゴリを変更します。

public class Square implements Quadrangle {
    private long length;

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    public long getWidth() {
        return 0;
    }

    public long getHeight() {
        return 0;
    }
}

我々は四角形四角形の中にクラスのサイズ変更パラメータ()メソッドを置く場合は、この時点では、内部方法が与えられます。正方形のスクエアは何にsetWidth()とsetHeightメソッドを持っていないので()メソッドを持っています。したがって、継承の増殖、リサイズ()メソッドのパラメータ缶のみ長方形長方形を制限するためです。もちろん、我々は徹底的にデザインモードコースの後半で説明していきます。

多重化の原則の合成

原則(コンポジット/骨再利用原理、CARP)を多重合成ではなく、ソフトウェアの再利用の継承の目的のため、可能な物体組成物(HAS-)/重合(contanis - )を指します。あなたは、クラスとクラス間の結合を低減するために、システムをより柔軟にすることができ、他のクラスのクラスの影響で比較的小さな変化が生じました。私たちの継承は、実装の詳細の全てに相当し、ホワイトボックスの再利用は、サブクラスにさらされていると呼ばれています。また、ブラックボックス多重オブジェクトとして知られている組成物/重合は、クラスの実装の詳細を外部からアクセスすることができません。特定のビジネスシナリオに基づいてコードの設計を行うには、実際には、OOPモデルに従う必要があります。あるいは、データベース操作中に、例えば、最初のDBConnectionカテゴリを作成します。

public class DBConnection { 
    public String getConnection(){ 
        return "MySQL 数据库连接"; 
    } 
}

ProductDaoカテゴリを作成:

public class ProductDao{ 
    private DBConnection dbConnection; 
    public void setDbConnection(DBConnection dbConnection) { 
        this.dbConnection = dbConnection; 
    }
    public void addProduct(){ 
        String conn = dbConnection.getConnection(); 
        System.out.println("使用"+conn+"增加产品"); 
    } 
}

これは、原則シナリオを多重化する非常に典型的な合成です。しかし、現在の設計は、のDBConnectionは抽象化ではなく、簡単にシステムの拡張ではありません。現在のシステムは、ビジネスの変化、データベース操作は、Oracleデータベース層を支持することを想定し、MySQLデータベースの接続をサポートしています。もちろん、我々は中のDBConnectionでのOracleデータベースメソッドのサポートを追加することができます。しかし、開閉の原則に反します。実際には、我々はコードダオを変更する必要はありません、のDBConnectionはコードで抽象的、外観を変更します:

public abstract class DBConnection { 
    public abstract String getConnection(); 
}

その後、ロジックは、MySQLを引っ張っ:

public class MySQLConnection extends DBConnection { 
    @Override 
    public String getConnection() { 
        return "MySQL 数据库连接"; 
    } 
}

Oracleは、論理の支援を再作成します。

public class OracleConnection extends DBConnection { 
    @Override 
    public String getConnection() { 
        return "Oracle 数据库连接"; 
    } 
}

アプリケーション層への特定の選択は、クラス図を見て:

設計原理の概要

基本的なデザインパターンを学習し、設計原理を学びます。実際の開発プロセスでは、必ずしもすべてのコードは、設計原理に従うことを要求し、私たちは人材、時間、コスト、品質、完璧ではなく、意図的に追求を考慮する必要があり、適切な場面での設計原則に従うことを、トレードオフのようなものを体現、私たちは、よりエレガントなコードの構造を設計するのに役立ちます。

おすすめ

転載: www.cnblogs.com/whgk/p/12465380.html