常用設(shè)計(jì)原則和設(shè)計(jì)模式

常用的設(shè)計(jì)原則

  • 開閉原則(Open Close Principle)

對(duì)擴(kuò)展開放對(duì)修改關(guān)閉,為了使程序的擴(kuò)展性好,易于維護(hù)和升級(jí)。

  • 里氏代換原則(Liskov Substitution Principle)

任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn),多使用多態(tài)的方式。

  • 依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)

盡量多依賴于抽象類或接口而不是具體實(shí)現(xiàn)類,對(duì)子類具有強(qiáng)制性和規(guī)范性

  • 接口隔離原則(Interface Segregation Principle)

盡量多使用小接口而不是大接口,避免接口的污染,降低類之間耦合度。

  • 迪米特法則(最少知道原則)(Demeter Principle)

一個(gè)實(shí)體應(yīng)當(dāng)盡量少與其他實(shí)體之間發(fā)生相互作用,使系統(tǒng)功能模塊相對(duì)獨(dú)立。高內(nèi)聚,低耦合。

  • 合成復(fù)用原則(Composite Reuse Principle)

盡量多使用合成/聚合的方式,而不是繼承的方式。


常用的設(shè)計(jì)模式

設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
設(shè)計(jì)模式就是一種用于固定場(chǎng)合的固定套路。

  • 創(chuàng)建型模式 - 單例設(shè)計(jì)模式、工廠方法模式、抽象工廠模式、建造者模式、原型模式
  • 結(jié)構(gòu)型模式 - 裝飾器模式、代理模式、適配器模式、橋接模式、組合模式、外觀模式、享元模式
  • 行為型模式 - 模板設(shè)計(jì)模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、接解釋器模式、狀態(tài)模式、策略模式、職責(zé)鏈模式、訪問(wèn)者模式。

單例設(shè)計(jì)模式

單例設(shè)計(jì)模式主要分為:餓漢式 和 懶漢式,懶漢式需要對(duì)多線程進(jìn)行同步處理。
餓漢模式 (立即加載, 線程安全, 推薦):類加載慢, 運(yùn)行時(shí)獲取對(duì)象快

/*
   餓漢式
 */
public class Singleton {
     // 2. 使用private static 共同修飾對(duì)象的引用
    private static Singleton sin = new Singleton();

     //1. 私有化構(gòu) 方法 使用private關(guān)鍵字修飾
    private Singleton(){ }

   // 3.  提供公有的get方法將對(duì)象返回出去,用public static共同修飾
    public static Singleton getInstance(){
        return sin;
    }

}

懶漢模式 (延遲加載, 非線程安全):類加載快, 運(yùn)行時(shí)獲取對(duì)象慢

/*
   懶漢式--雙重鎖(適用于多線程)
 */

public class Singleton {

    // 2.聲明本類類型的引用指向本類類型的對(duì)象并使用private static關(guān)鍵字修飾
    private static Singleton sin = null;

    // 1.私有化構(gòu)造方法,使用private關(guān)鍵字修飾
    private Singleton() {}

    // 3.提供公有的get方法負(fù)責(zé)將上述對(duì)象返回出去,使用public static關(guān)鍵字修飾
    public static Singleton getInstance() {
      
        if (null == sin) {
            synchronized (Singleton.class) {
                if (null == sin) {
                    sin = new Singleton();
                }
            }
        }
        return sin;
    }
}

工廠方法模式

  • 普通工廠模式:

普通工廠方法模式就是建立一個(gè)工廠類,對(duì)實(shí)現(xiàn)了同一接口的不同實(shí)現(xiàn)類進(jìn)行實(shí)例的創(chuàng)建。

Send接口:

public interface Sender {
    // 自定義抽象方法來(lái)描述發(fā)送的行為
    void send();
}

Send實(shí)現(xiàn)類:

/*
   短信形式發(fā)送...
 */
public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("正在發(fā)送短信...");
    }
}

/*
   郵件形式發(fā)送...
 */
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("正在發(fā)送郵件...");
    }
}

普通工廠:

public class SendFactory {
    // 自定義成員方法實(shí)現(xiàn)對(duì)象的創(chuàng)建
    public Sender produce(String type) {
        
        if ("mail".equals(type)) {
            return new MailSender();
        }
        if ("sms".equals(type)) {
            return new SmsSender();
        }
        return null;
    }

測(cè)試:

public class SendFactoryTest {

    public static void main(String[] args) {

        // 缺點(diǎn):代碼復(fù)雜,可讀性略差
        // 優(yōu)點(diǎn):擴(kuò)展性和可維護(hù)性更強(qiáng)!  尤其是在創(chuàng)建大量對(duì)象的前提下
        // 1.聲明工廠類類型的引用指向工廠類類型的對(duì)象
        SendFactory sf = new SendFactory();

        // 2.調(diào)用生產(chǎn)方法來(lái)實(shí)現(xiàn)對(duì)象的創(chuàng)建
        Sender sender = sf.produce("mail");
        
        // 3.使用對(duì)象調(diào)用方法模擬發(fā)生的行為
        sender.send();  //  輸出:正在發(fā)送郵件...

    }
}

主要缺點(diǎn) :在普通工廠方法模式中,如果傳遞的字符串出錯(cuò),則不能正確創(chuàng)建對(duì)象,并且可能出現(xiàn)空指針異常。

  • 多個(gè)工廠方法模式:

多個(gè)工廠:

public class SendFactory {
    // 自定義成員方法實(shí)現(xiàn)對(duì)象的創(chuàng)建
    public Sender produce(String type) {
        
        if ("mail".equals(type)) {
            return new MailSender();
        }
        if ("sms".equals(type)) {
            return new SmsSender();
        }
        return null;
    }

    public Sender produceMail() {
        return new MailSender();
    }
    public Sender produceSms() {
        return new SmsSender();
    }
}

測(cè)試:

public class SendFactoryTest {

    public static void main(String[] args) {

        // 缺點(diǎn):代碼復(fù)雜,可讀性略差
        // 優(yōu)點(diǎn):擴(kuò)展性和可維護(hù)性更強(qiáng)!  尤其是在創(chuàng)建大量對(duì)象的前提下
        // 1.聲明工廠類類型的引用指向工廠類類型的對(duì)象
        SendFactory sf = new SendFactory();

        // 2.調(diào)用生產(chǎn)方法來(lái)實(shí)現(xiàn)對(duì)象的創(chuàng)建
        Sender sender = sf.produceMail;  //多個(gè)工廠
        
        // 3.使用對(duì)象調(diào)用方法模擬發(fā)生的行為
        sender.send();  //  輸出:正在發(fā)送郵件...

    }
}

主要缺點(diǎn) :在多個(gè)工廠方法模式中,為了能夠正確創(chuàng)建對(duì)象,先需要?jiǎng)?chuàng)建工廠類的對(duì)象才能調(diào)用工廠類中的生產(chǎn)方法。

  • 靜態(tài)工廠方法模式:

靜態(tài)工廠:

public class SendFactory {
    // 自定義成員方法實(shí)現(xiàn)對(duì)象的創(chuàng)建
    public Sender produce(String type) {
        //System.out.println("隨便加一句打印進(jìn)行測(cè)試");
        if ("mail".equals(type)) {
            return new MailSender();
        }
        if ("sms".equals(type)) {
            return new SmsSender();
        }
        return null;
    }

    public static Sender produceMail() {
        return new MailSender();
    }
    public static Sender produceSms() {
        return new SmsSender();
    }
}

測(cè)試:


public class SendFactoryTest {

    public static void main(String[] args) {

        // 缺點(diǎn):代碼復(fù)雜,可讀性略差
        // 優(yōu)點(diǎn):擴(kuò)展性和可維護(hù)性更強(qiáng)!  尤其是在創(chuàng)建大量對(duì)象的前提下
        // 1.聲明工廠類類型的引用指向工廠類類型的對(duì)象
        //SendFactory sf = new SendFactory();

        // 2.調(diào)用生產(chǎn)方法來(lái)實(shí)現(xiàn)對(duì)象的創(chuàng)建
        //Sender sender = sf.produce("mail");
        //Sender sender = sf.produce("maill");
        //Sender sender = sf.produceMail();
        Sender sender = SendFactory.produceMail();  //靜態(tài)工廠

        // 3.使用對(duì)象調(diào)用方法模擬發(fā)生的行為
        sender.send();

    }
}

工廠方法模式適合:凡是出現(xiàn)了大量的產(chǎn)品需要?jiǎng)?chuàng)建且具有共同的接口時(shí),可以通過(guò)工廠方法模式進(jìn)行創(chuàng)建。

主要缺點(diǎn) :

工廠方法模式有一個(gè)問(wèn)題就是,類的創(chuàng)建依賴工廠類,也就是說(shuō),如果想要拓展程序生產(chǎn)新的產(chǎn)品,就必須對(duì)工廠類的代碼進(jìn)行修改,這就違背了開閉原則。

抽象工廠模式

圍繞一個(gè)超級(jí)工廠創(chuàng)建其他工廠。該超級(jí)工廠又稱為其他工廠的工廠。

抽象工廠模式提供了一個(gè)創(chuàng)建一系列相關(guān)或者相互依賴對(duì)象的接口,無(wú)需指定他們具體的類。

就拿上面的例子來(lái)講,抽象工廠模式對(duì)比上面的工廠方法模式區(qū)別就是:工廠方法模式是一個(gè)工廠類(SendFactory )中有兩個(gè)生產(chǎn)方法(produceMail()和produceSms())。而抽象工廠就是兩個(gè)工廠類各自有一個(gè)生產(chǎn)方法,然后讓兩個(gè)工廠類實(shí)現(xiàn)同一個(gè)接口。

適用場(chǎng)景:

  • 客戶端不依賴于產(chǎn)品類實(shí)例如何被創(chuàng)建、實(shí)現(xiàn)等細(xì)節(jié)。

  • 強(qiáng)調(diào)一系列相關(guān)的產(chǎn)品對(duì)象(屬于同一產(chǎn)品族)一起使用創(chuàng)建對(duì)象需要大量的重復(fù)代碼。

  • 提供一個(gè)產(chǎn)品類的庫(kù),所有的產(chǎn)品以同樣的接口出現(xiàn),從而使得客戶端不依賴于具體的實(shí)現(xiàn)。

優(yōu)點(diǎn):

  • 具體產(chǎn)品在應(yīng)用層的代碼隔離,無(wú)需關(guān)心創(chuàng)建的細(xì)節(jié)。

  • 將一個(gè)系列的產(chǎn)品統(tǒng)一到一起創(chuàng)建。

總結(jié):

1、簡(jiǎn)單工廠模式(靜態(tài)工廠模式):雖然某種程度上不符合設(shè)計(jì)原則,但實(shí)際使用最多。

2、工廠方法模式:不修改已有類的前提上,通過(guò)增加新的工廠類實(shí)現(xiàn)擴(kuò)展。

3、抽象工廠模式:不可以增加產(chǎn)品,可以增加產(chǎn)品族。

應(yīng)用場(chǎng)景:

1、JDk中Calendar的getInstance方法

2、JDBC中的Connection對(duì)象的獲取

3、Spring中IOC容器創(chuàng)建管理bean對(duì)象

4、反射中Class對(duì)象的newInstance方法

核心本質(zhì):
  • 實(shí)例化對(duì)象不使用new,用工廠方法替代。

  • 將選擇實(shí)現(xiàn)類,創(chuàng)建對(duì)象統(tǒng)一管理和控制,從而將調(diào)用者跟我們的實(shí)現(xiàn)類解耦。

裝飾器模式

裝飾器模式就是給一個(gè)對(duì)象動(dòng)態(tài)的增加一些新功能,要求裝飾對(duì)象和被裝飾對(duì)象實(shí)現(xiàn)同一個(gè)接口,裝飾對(duì)象持有被裝飾對(duì)象的實(shí)例。

實(shí)際意義:

可以實(shí)現(xiàn)一個(gè)類功能的擴(kuò)展??梢詣?dòng)態(tài)的增加功能,而且還能動(dòng)態(tài)撤銷(繼承不行)。

缺點(diǎn):產(chǎn)生過(guò)多相似的對(duì)象,不易排錯(cuò)。

代理模式

  • 代理模式就是找一個(gè)代理類替原對(duì)象進(jìn)行一些操作。

  • 如果在使用的時(shí)候需要對(duì)原有的方法進(jìn)行改進(jìn),可以采用一個(gè)代理類調(diào)用原有方法,并且對(duì)產(chǎn)生的結(jié)果進(jìn)行控制,這種方式就是代理模式。

  • 使用代理模式,可以將功能劃分的更加清晰,有助于后期維護(hù)。

接口:

public interface Sourceable {
    // 自定義抽象方法
    void method();
}

真實(shí)對(duì)象:

public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("--我是真實(shí)對(duì)象,也就是被代理的對(duì)象(房東)");
    }
}

代理對(duì)象:

public class Proxy implements Sourceable {
    private Source source;

    public Proxy() {
        source = new Source();
    }

    @Override
    public void method() {
        source.method();
        System.out.println("我是代理對(duì)象?。ㄖ薪椋?);
    }
}

訪問(wèn)測(cè)試

public class SourceableTest {

    public static void main(String[] args) {

         // 使用代理類實(shí)現(xiàn)功能(找中介租房)
        Sourceable sourceable = new Proxy();
        sourceable.method();
    }
}
代理模式和裝飾器模式的比較:
  • 裝飾器模式通常的做法是將原始對(duì)象作為一個(gè)參數(shù)傳給裝飾者的構(gòu)造器,而代理模式通常在一個(gè)代理類中創(chuàng)建一個(gè)被代理類的對(duì)象。
  • 裝飾器模式關(guān)注于在一個(gè)對(duì)象上動(dòng)態(tài)的添加方法,然而代理模式關(guān)注于控制對(duì)對(duì)象的訪問(wèn)。

模板設(shè)計(jì)模式

模板方法模式主要指一個(gè)抽象類中封裝了一個(gè)固定流程,流程中的具體步驟可以由不同子類進(jìn)行不同的實(shí)現(xiàn),通過(guò)抽象類讓固定的流程產(chǎn)生不同的結(jié)果。

實(shí)際意義:
  • 將多個(gè)子類共有且邏輯基本相同的內(nèi)容提取出來(lái)實(shí)現(xiàn)代碼復(fù)用。
  • 不同的子類實(shí)現(xiàn)不同的效果形成多態(tài),有助于后期維護(hù)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容