成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Java設(shè)計(jì)模式學(xué)習(xí)總結(jié)

songze / 429人閱讀

摘要:的設(shè)計(jì)模式世界頂級(jí)足球射門(mén)錦集。重構(gòu)敏捷軟件開(kāi)發(fā)設(shè)計(jì)模式解析一場(chǎng)場(chǎng)最精彩的足球比賽。但不屬于種設(shè)計(jì)模式之一。代理設(shè)計(jì)模式代理模式,為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。

前言

編程是一門(mén)技術(shù),更是一門(mén)藝術(shù)。
如果想成為一名更優(yōu)秀的軟件設(shè)計(jì)師,了解優(yōu)秀軟件設(shè)計(jì)的演變過(guò)程比學(xué)習(xí)優(yōu)秀設(shè)計(jì)本身更有價(jià)值,因?yàn)樵O(shè)計(jì)的演變過(guò)程中蘊(yùn)藏著大智慧。
學(xué)習(xí)設(shè)計(jì)模式,重要的不是你將來(lái)會(huì)不會(huì)用得到這些模式,而是通過(guò)這些模式讓你找到“封裝變化”,“對(duì)象間松散耦合”,“針對(duì)接口編程”的感覺(jué),從而設(shè)計(jì)出易維護(hù),易擴(kuò)展,易復(fù)用,靈活性好的程序。
成為詩(shī)人后可能不需要刻意地按照某種模式去創(chuàng)作,但成為詩(shī)人前他們一定是認(rèn)真地研究過(guò)成百上千的唐詩(shī)宋詞,古今名句。

GOF的《設(shè)計(jì)模式》:世界頂級(jí)足球射門(mén)錦集。
《重構(gòu)》《敏捷軟件開(kāi)發(fā)》《設(shè)計(jì)模式解析》:一場(chǎng)場(chǎng)最精彩的足球比賽。
球迷(軟件使用者)——>足球運(yùn)動(dòng)員(軟件設(shè)計(jì)編程者)——>球星(軟件架構(gòu)師)

UML類(lèi)圖


類(lèi)圖:
類(lèi)圖分三層。
第一層顯示類(lèi)的名稱,如果是抽象類(lèi),用斜體表示。
第二層是類(lèi)的特性,通常是字段和屬性。
第三層是類(lèi)的操作,通常是方法和行為。
注意:"+"表示public,"-"表示private,"#"表示protected。

接口圖:
與類(lèi)圖的區(qū)別主要是頂端有<>顯示。
第一行:接口名稱。
第二行:接口方法。
接口還有另外一種表示方法,俗稱棒棒糖表示法。

類(lèi)與類(lèi),類(lèi)與接口的關(guān)系:
繼承關(guān)系:空心三角+實(shí)線來(lái)表示。
實(shí)現(xiàn)接口:空心三角+虛線表示。
關(guān)聯(lián)關(guān)系:實(shí)線箭頭表示。
聚合關(guān)系:用空心菱形+實(shí)線箭頭表示。
大雁和雁群。聚合表示一種弱的"擁有"關(guān)系,體現(xiàn)的是A對(duì)象可以包含B對(duì)象,但B對(duì)象不是A對(duì)象的一部分。
合成(組合)關(guān)系:實(shí)心菱形+實(shí)線箭頭表示。
鳥(niǎo)和翅膀。合成(組合)關(guān)系是一種強(qiáng)的"擁有"關(guān)系,體現(xiàn)了嚴(yán)格的部分和整體的關(guān)系,部分和整體的生命周期一樣。
依賴關(guān)系:虛線箭頭表示。

簡(jiǎn)單工廠模式

定義:簡(jiǎn)單工廠模式是屬于創(chuàng)建型模式,又叫做靜態(tài)工廠方法(Static Factory Method)模式,是由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類(lèi)的實(shí)例。但不屬于23種GOF設(shè)計(jì)模式之一。
實(shí)現(xiàn)方法和角色:
(1)實(shí)現(xiàn)方式:簡(jiǎn)單工廠模式的實(shí)質(zhì)是由一個(gè)工廠類(lèi)根據(jù)傳入的參數(shù),動(dòng)態(tài)決定應(yīng)該創(chuàng)建哪一個(gè)產(chǎn)品類(lèi)(這些產(chǎn)品類(lèi)繼承自一個(gè)父類(lèi)或接口)的實(shí)例。
(2)角色:
工廠(Creator)角色
抽象產(chǎn)品(Product)角色
具體產(chǎn)品(Concrete Product)角色
優(yōu)缺點(diǎn):
(1)優(yōu)點(diǎn):在于工廠類(lèi)中包含了必要的邏輯,根據(jù)客戶需要的條件動(dòng)態(tài)實(shí)例化相關(guān)的類(lèi),對(duì)客戶端來(lái)說(shuō),去掉了與具體產(chǎn)品的依賴。
(2)缺點(diǎn):工廠類(lèi)集中了所有實(shí)例的創(chuàng)建邏輯,當(dāng)增加新的產(chǎn)品時(shí),會(huì)違反開(kāi)放-封閉原則。

簡(jiǎn)單工廠模式結(jié)構(gòu)圖:

//抽象產(chǎn)品
public abstract class Computer {
    public abstract void start();
}

//具體產(chǎn)品
public class LenovoComputer extends Computer {
    public void start() {
        System.out.println("聯(lián)想電腦啟動(dòng)");
    }
}

public class HpComputer extends Computer {
    public void start() {
        System.out.println("惠普電腦啟動(dòng)");
    }
}

public class AsusComputer extends Computer {
    public void start() {
        System.out.println("華碩電腦啟動(dòng)");
    }
}

//工廠類(lèi)
public class ComputerFactory {
    public static Computer createComputer(String type) {
        Computer computer = null;
        if("lenovo".equals(type)){
            computer = LenovoComputer();
        } else if("hp".equals(type)){
            computer = HpComputer();
        } else if("asus".equals(type)){
            computer = AsusComputer();
        }
        return computer;
    }
}

//客戶端調(diào)用
public class Client {
    public static void main(String[] args) {
        ComputerFactory.createComputer("lenovo").start();
    }
}

面試題:請(qǐng)用C++,Java,C#,或VB.NET任意一種面向?qū)ο笳Z(yǔ)言實(shí)現(xiàn)一個(gè)計(jì)算器控制臺(tái)程序,要求輸入兩個(gè)數(shù)和運(yùn)算符號(hào),得到結(jié)果。

活字印刷

易維護(hù):要改,只需要改要改之字。

可復(fù)用:每個(gè)字在印刷中可重復(fù)使用。

易擴(kuò)展:要加字,只需另刻字加入。

靈活性好:字可任意排序。

面向?qū)ο蟮姆治鲈O(shè)計(jì)編程思想:考慮通過(guò)封裝,繼承,多態(tài)把程序的耦合度降低,用設(shè)計(jì)模式使得程序更加靈活,容易修改,并且易于復(fù)用。
初級(jí)程序員的工作就是:Ctrl+C和Ctrl+V。
編程有一個(gè)原則:用盡可能的辦法避免重復(fù)。代碼重復(fù)到一定程度,維護(hù)就是一場(chǎng)災(zāi)難。
復(fù)制粘貼是最容易的編程,也是最沒(méi)有價(jià)值的編程。

封裝:
業(yè)務(wù)封裝,將界面邏輯和業(yè)務(wù)邏輯分開(kāi)。降低耦合度,達(dá)到易維護(hù)。
繼承:
將加減乘除等運(yùn)算分離。修改或增加新的運(yùn)算方法,不影響原有功能,降低風(fēng)險(xiǎn)。
多態(tài)+簡(jiǎn)單工廠模式
實(shí)例化哪個(gè)運(yùn)算對(duì)象?應(yīng)該用一個(gè)多帶帶的類(lèi)來(lái)做這個(gè)創(chuàng)建實(shí)例的過(guò)程,這就是工廠。

public abstract class Operate {
    public double numberA;
    public double numberB;
    public abstract double getResult();
    //TODO get set 方法
}

public Class OperateAdd extends Operate {
    public double getResult(){
        return numberA + numberB;
    }
}

public Class OperateSub extends Operate {
    public double getResult(){
        return numberA - numberB;
    }
}

public Class OperateMul extends Operate {
    public double getResult(){
        return numberA * numberB;
    }
}

public Class OperateDiv extends Operate {
    public double getResult() {
        return numberA / numberB;
    }
}

public Class OperateFactory {
    public static Operate createOperate(String oper){
        Operate operate = null;
        if("+".equal(oper)){
            operate = new OperateAdd();
        } else if("-".equal(oper)){
            operate = new OperateSub();
        } else if("*".equal(oper)){
            operate = new OperateMul();
        } else if("/".equal(oper)){
            operate = new OperateDiv();
        }
        return operate;
    }
}

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.println("請(qǐng)輸入一個(gè)數(shù)字A:");
    double numberA = scanner.nextDouble();
    System.out.println("請(qǐng)輸入一個(gè)運(yùn)算符(+,-,*,/):");
    String oper = scanner.next();
    System.out.println("請(qǐng)輸入一個(gè)數(shù)字B:");
    double numberB = scanner.nextDouble();
    Operate operate = OperateFactory.createOperate(oper);
    operate.setNumberA(numberA);
    operate.setNumberB(numberB);
    System.out.println(operate.getResult());   
}

使用場(chǎng)景:
工廠類(lèi)負(fù)責(zé)創(chuàng)建的對(duì)象比較少。
客戶只知道傳入工廠類(lèi)的參數(shù),對(duì)于如何創(chuàng)建對(duì)象(邏輯)不關(guān)心。
優(yōu)點(diǎn):
使用戶根據(jù)參數(shù)獲得相應(yīng)的類(lèi)實(shí)例,避免了直接實(shí)例化,降低了耦合性。
缺點(diǎn):
增加新類(lèi)型,需要修改工廠,違背了開(kāi)放封閉原則。
簡(jiǎn)單工廠需要知道所有要生成的類(lèi)型,當(dāng)子類(lèi)過(guò)多或者子類(lèi)層次過(guò)多時(shí)不適合使用。

不能只滿足于寫(xiě)完代碼運(yùn)行結(jié)果正確就完事,時(shí)常考慮如何讓代碼更加簡(jiǎn)練,更加容易維護(hù),容易擴(kuò)展和復(fù)用,只有這樣才可以真正得到提高。

工廠方法模式

定義:定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類(lèi)決定實(shí)例化哪個(gè)類(lèi)。工廠方法使一個(gè)類(lèi)的實(shí)例化延遲到其子類(lèi)。
依賴倒置原則
工廠方法模式:克服了簡(jiǎn)單工廠違背"開(kāi)發(fā)-封閉原則"的缺點(diǎn),又保持了封裝對(duì)象創(chuàng)建過(guò)程的優(yōu)點(diǎn)。
工廠方法模式是簡(jiǎn)單工廠模式的進(jìn)一步抽象和推廣。由于使用了多態(tài)性,工廠方法模式保持了簡(jiǎn)單工廠模式的優(yōu)點(diǎn),而且克服了它的缺點(diǎn)。缺點(diǎn):每加一個(gè)產(chǎn)品,就需要加一個(gè)產(chǎn)品工廠類(lèi),增加了額外的開(kāi)發(fā)量。
工廠方法模式(Factory Method)結(jié)構(gòu)圖:

常規(guī)實(shí)現(xiàn):

通過(guò)反射實(shí)現(xiàn):

//抽象產(chǎn)品
public abstract class Computer {
    public abstract void start();
}

//具體產(chǎn)品
public LenovoComputer extends Computer {
    public void start() {
        System.out.println("聯(lián)想電腦啟動(dòng)");
    }
}

public HpComputer extends Computer {
    public void start() {
        System.out.println("惠普電腦啟動(dòng)");
    }
}

public AsusComputer extends Computer {
    public void start() {
        System.out.println("華碩電腦啟動(dòng)");
    }
}

//抽象工廠
public abstract class ComputerFactory {
    public abstract  T createComputer(Class clz);
}

//具體工廠
public class ConcreteFactory extends ComputerFactory {
    public  T createComputer(Class clz) {
        Computer computer = null;
        String className =clz.getName();
        try{
           computer = (Computer)Class.forName(className).netInstance(); 
        }catch(Exception e) {
            e.printStackTrace();
        }
        return (T)computer;
    }
}

//客戶端調(diào)用
public class Client {
    public static void main(String[] args) {
        ComputerFactory computerFactory = new ConcreteFactory();
        Computer computer = null;        
        computer = computerFactory.createComputer(LenovoComputer.class);
        computer.start();
        computer = computerFactory.createComputer(HpComputer.class);
        computer.start();
        computer = computerFactory.createComputer(AsusComputer.class);
        computer.start();
    }
}

這樣整個(gè)工廠和產(chǎn)品體系其實(shí)都沒(méi)有修改的變化,而只是擴(kuò)展的變化,這就完全符合了開(kāi)放-封閉原則。
工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來(lái)實(shí)現(xiàn)運(yùn)算類(lèi),工廠方法把簡(jiǎn)單工廠的內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端代碼來(lái)進(jìn)行。

抽象工廠模式

定義:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無(wú)需指定他們具體的類(lèi)。
當(dāng)需要?jiǎng)?chuàng)建的產(chǎn)品有多個(gè)產(chǎn)品線(產(chǎn)品族)時(shí),使用抽象工廠模式是比較好的選擇。
那什么是多個(gè)產(chǎn)品線?聯(lián)想和惠普的電腦,電腦也有多個(gè)產(chǎn)品線:臺(tái)式機(jī)、筆記本和平板。聯(lián)想和惠普都在生產(chǎn)這些不同產(chǎn)品線上的電腦,使用工廠方法模式已經(jīng)滿足不了需求,可用抽象工廠模式來(lái)解決。

抽象工廠(Abstract Factory)模式結(jié)構(gòu)圖:

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

//抽象產(chǎn)品
public abstract class DesktopComputer {
    public abstract void start();
}

public abstract class NotebookComputer {
    public abstract void start();
}

//具體產(chǎn)品
public LenovoDesktopComputer extends DesktopComputer {
    public void start() {
        System.out.println("聯(lián)想臺(tái)式機(jī)啟動(dòng)");
    }
}

public HpDesktopComputer extends DesktopComputer {
    public void start(){
        System.out.println("惠普臺(tái)式機(jī)啟動(dòng)");
    }
}

public LenovoNotebookComputer extends NotebookComputer {
    public void start() {
        System.out.println("聯(lián)想筆記本啟動(dòng)");
    }
}

public HpNotebookComputer extends NotebookComputer {
    public void start() {
        System.out.println("惠普筆記本啟動(dòng)");
    }
}

//抽象工廠
public abstract class ComputerFactory {
    public abstract DesktopComputer createDesktopComputer();
    public abstract NotebookComputer  createNotebookComputer();
}

//具體工廠
public class LenovoFactory extends ComputerFactory {
    public DesktopComputer createDesktopComputer() {
        return new LenovoDesktopComputer();
    }
    
    public NotebookComputer createNotebookComputer() {
        return new LenovoNotebookComputer();
    }    
}

public class HpFactory extends ComputerFactory {
    public DesktopComputer createDesktopComputer() {
        return new HpDesktopComputer();
    }
    public NotebookComputer createNotebookComputer() {
        return new HpNoteBookComputer();
    }
}

//客戶端調(diào)用
public class Client {
    public static void main(String[] args) {
        ComputerFactory lenovoFactory = new LenovoFactory();
        lenovoFactory.createDesktopComputer().start();
        lenovoFactory.createNotebookComputer().start();
        ComputerFactory hpFactory = new HpFactory();
        hpFactory.createDesktopComputer().start();
        hpFactory.createNotebookComputer().start();
    }
}

抽象工廠模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
具體類(lèi)的創(chuàng)建實(shí)例過(guò)程與客戶端分離,客戶端通過(guò)工廠的抽象接口操縱實(shí)例,客戶端并不知道具體的實(shí)現(xiàn)是誰(shuí)。
缺點(diǎn):
如果增加新的產(chǎn)品族則也需要修改抽象工廠和所有的具體工廠。

策略設(shè)計(jì)模式

策略設(shè)計(jì)模式(Strategy):它定義了算法家族,分別封裝起來(lái),讓它們之間可以互相替換,此模式讓算法的變化,不會(huì)影響到使用算法的客戶。

面試題:請(qǐng)用任意面向?qū)ο笳Z(yǔ)言,設(shè)計(jì)實(shí)現(xiàn)一個(gè)商場(chǎng)收銀功能,需包含:打折(9折,8折,五折),返現(xiàn)(滿300返100,滿100返50),及正常價(jià)格收費(fèi)。

面向?qū)ο缶幊?,并不是?lèi)越多越好,類(lèi)的劃分是為了封裝,但分類(lèi)的基礎(chǔ)是抽象,具有相同屬性和功能的對(duì)象的抽象集合才是類(lèi)。
商場(chǎng)促銷(xiāo),無(wú)論是打折還是返現(xiàn),其實(shí)都是一些算法,但算法本身只是一種策略,最重要的是這些算法隨時(shí)都可能互相替換,這就是變化點(diǎn),封裝變化點(diǎn)是我們面向?qū)ο蟮囊环N很重要的思維方式。

現(xiàn)金收費(fèi)抽象類(lèi)。

正常收費(fèi)子類(lèi)。

打折收費(fèi)子類(lèi)。

返現(xiàn)收費(fèi)子類(lèi)。

//現(xiàn)金收費(fèi)抽象類(lèi)
public abstract class CashSuper {
    public abstarct double acceptCash(double money);
}

//正常收費(fèi)子類(lèi)
public class CashNormal extends CashSuper {
    public double acceptCash(double money) {
        return money;
    }
}

//打折收費(fèi)子類(lèi)
public class CashRebate extends CashSuper {
    private double rebate;
    
    public CashRebate(double rebate){
        this.rebate = rebate;
    }
    
    public double acceptyCash(double money) {
        return money * rebate;
    }    
}

//返現(xiàn)收費(fèi)子類(lèi)
public class CashReturn extends CashSuper {
    private double moneyCondition;
    private double moneyReturn;
    
    public CashReturn(double moneyCondition,double moneyReturn) {
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    
    public double acceptCash(double money) {
        double resule = money;
        if(money >= moneyCondition){
            result = money - Math.floor(money / moneyCondition) * moneyReturn ;
            return result;
        }
    }  
}

//上下文,維護(hù)一個(gè)對(duì)Strategy對(duì)象的引用
public class CashContext {
    private CashSuper cashSuper;
    
    public CashContext (CashSuper cashSuper) {
        this.cashSuper = cashSuper;
    }
    
    public double getResult(double money){
        return cashSuper.acceptCash(money);
    }  
}

    策略模式和簡(jiǎn)單工廠模式結(jié)合,將客戶端條件判斷轉(zhuǎn)移到CashContext中。
    客戶端調(diào)用略

總結(jié):
當(dāng)不同的行為堆砌在一個(gè)類(lèi)中,就很難避免使用條件語(yǔ)句來(lái)選擇合適的行為。將這些行為封裝在一個(gè)個(gè)獨(dú)立的Strategy類(lèi)中,可以在使用這些行為的類(lèi)中消除條件語(yǔ)句。
策略模式封裝了變化。
策略模式就是用來(lái)封裝算法的,只要在分析的過(guò)程中聽(tīng)到需要在不同的時(shí)間應(yīng)用不同的業(yè)務(wù)規(guī)則,就可以考慮是使用策略模式。
消除switch或條件判斷:反射技術(shù)。

代理設(shè)計(jì)模式

代理模式(Proxy),為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。
為什么要有代理模式?
開(kāi)閉原則,對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
為什么有靜態(tài)代理和動(dòng)態(tài)代理?
最大的缺點(diǎn):接口變化了,除了實(shí)現(xiàn)類(lèi)需要改變,代理也需要修改。實(shí)際上我們是不想讓代理也需要修改的。所以出現(xiàn)了動(dòng)態(tài)代理。
jdk 動(dòng)態(tài)代理的缺點(diǎn)?
必須要實(shí)現(xiàn)接口。
jdk動(dòng)態(tài)代理為什么必須要實(shí)現(xiàn)接口?
因?yàn)樗J(rèn)繼承的proxy類(lèi),java是單繼承,所以必須要實(shí)現(xiàn)接口。
spring aop 最核心的思想:動(dòng)態(tài)代理。
什么樣的場(chǎng)景下用cglib?
看代理的對(duì)象有沒(méi)有接口,沒(méi)有接口的用cglib。
代理模式使用場(chǎng)景
無(wú)法或者不想直接訪問(wèn)某個(gè)對(duì)象時(shí)可以通過(guò)一個(gè)代理對(duì)象來(lái)間接的訪問(wèn)。

//靜態(tài)代理
//接口
public interface IuserDao {
    void save();
}

//實(shí)現(xiàn)類(lèi)
public class UserDaoImpl implements IuserDao {
    public void save(){
        System.out.println("保存用戶");
    }
}

//代理類(lèi)
public class UserDaoProxy implements IUserDao {
    private IUserDao userDao;
    public UserDaoProxy(IUserDao userDao){
        this.userDao = userDao;
    }
    
    public void save(){
        System.out.println("操作前");
        userDao.svae();
        System.out.println("操作后");
    }
}

//測(cè)試
public static void main(String[] args) {
    //靜態(tài)代理
    IUserDao userDao = new UserDaoProxy(new UserDaoImpl());
    userDao.save();
    
    //動(dòng)態(tài)代理
    IUserDao userDao = (IUserDao)Proxy.newProxyInstance(IUserDao.class.getClassLoader,new Class[]{IuserDao.class},new InvocationHandler(){
        public Object invoke(Object proxy,Method method,Object[] args){
            System.out.println("操作前");
            Object object = method.invoke(new UserDaoImpl(),args);
            System.out.println("操作后");
            return object ;
        }
    });    
}
單例設(shè)計(jì)模式

定義:保證一個(gè)類(lèi)僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。

餓漢式(線程安全)

public class Singleton {
    private static Singleton instance = new Singleton();
    
    private Singleton(){
    }
    
    public static Singleton getInstance(){
        return instance;
    }   
}

這種方式在類(lèi)加載時(shí)就完成了初始化,所以類(lèi)加載較慢,但獲取對(duì)象的速度快。
基于類(lèi)加載機(jī)制避免了多線程的同步問(wèn)題。但是也不能確定有其他方式導(dǎo)致類(lèi)裝載。

懶漢式(線程不安全)

public class Singleton(){
    private static Singleton instance = null;
    
    private Singleton(){
        
    }
    
    public static Singleton getInstance(){
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

初始化時(shí)節(jié)約資源,第一次加載是需要實(shí)例化反映稍慢一些,多線程不能正常工作。

懶漢式(線程安全)

public class Singleton {
    private static Singleton instance = null;
    
    private Singleton(){}
    
    public static synchronized Singleton getInstance(){
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }   
}

每次調(diào)用getInstance方法時(shí)都需要同步,造成不必要的同步開(kāi)銷(xiāo),大部分時(shí)候是用不到同步的,所以不建議使用這種模式。

雙重檢查枷鎖(DCL)

public class Singleton {
    private volatile static Singleton instance = null;
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        if(instance == null) {
            synchroinzed(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    } 
}

這種寫(xiě)法在getSingleton方法中對(duì)singleton進(jìn)行了兩次判空,第一次是為了不必要的同步,第二次是在singleton等于null的情況下才創(chuàng)建實(shí)例。
DCL雖然在一定程度解決了資源的消耗和多余的同步,線程安全等問(wèn)題,但是他還是在某些情況會(huì)出現(xiàn)失效的問(wèn)題,也就是DCL失效,在《java并發(fā)編程實(shí)踐》一書(shū)建議用靜態(tài)內(nèi)部類(lèi)單例模式來(lái)替代DCL。

靜態(tài)內(nèi)部類(lèi)

public class Singleton {
    private Singleton(){}
    
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
    
    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }   
}

第一次加載Singleton類(lèi)時(shí)并不會(huì)初始化instance,只有第一次調(diào)用getInstance方法時(shí),虛擬機(jī)加載SingletonHolder并初始化instance,這樣不僅能確保線程安全也能保證Singleton類(lèi)的唯一性,所以推薦使用靜態(tài)內(nèi)部類(lèi)單例模式。

枚舉

public enum Singleton {
    INSTANCE;
}

總結(jié):
枚舉式是最簡(jiǎn)單最優(yōu)秀的單例寫(xiě)法,可以防止反射工具(《如何防止單例模式被Java反射攻擊》)和序列化破壞。《Effective Java》的作者Joshua Bloch推薦使用這種寫(xiě)法,只是用的人較少,沒(méi)有普遍性,建議編程時(shí)采用靜態(tài)內(nèi)部類(lèi)(不能防止反射和序列化破壞)。

模板方法模式

定義:定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類(lèi)中,模板方法使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
當(dāng)我們要完成一系列步驟,但其個(gè)別步驟在更詳細(xì)的層次上的實(shí)現(xiàn)可能不同時(shí),我們通??紤]使用模板方法模式來(lái)處理。
模板方法模式(TemplateMethod)結(jié)構(gòu)圖:

原型設(shè)計(jì)模式

定義:用原型實(shí)例指定創(chuàng)建對(duì)象的種類(lèi),并且通過(guò)拷貝這些原型創(chuàng)建新的對(duì)象。
原型模式其實(shí)就是從一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象,而且不需知道任何創(chuàng)建的細(xì)節(jié)。
一般在初始化信息不發(fā)生變化的情況下,克隆是最好的辦法,這既隱藏了創(chuàng)建對(duì)象的細(xì)節(jié),又對(duì)性能是大大的提高。
原型模式(Prototype)結(jié)構(gòu)圖:

Client:客戶端角色。
Prototype:抽象原型角色,抽象類(lèi)或者接口,用來(lái)聲明clone方法。
ConcretePrototype:具體的原型類(lèi),是客戶端角色使用的對(duì)象,即被復(fù)制的對(duì)象。

注意:Prototype通常是不用自己定義的,因?yàn)榭截愡@個(gè)操作十分常用,Java中就提供了Cloneable接口來(lái)支持拷貝操作,它就是原型模式中的Prototype。當(dāng)然,原型模式也未必非得去實(shí)現(xiàn)Cloneable接口,也有其他的實(shí)現(xiàn)方式。
Cloneable接口是一個(gè)標(biāo)識(shí)接口,表示這個(gè)對(duì)象是可拷貝的,只要重寫(xiě)clone方法就可以實(shí)現(xiàn)拷貝。clone方法不是在Cloneable接口中定義的(Cloneable接口中沒(méi)有定義任何方法),而是在Object中定義的。

//淺復(fù)制
public class BusinessCard implements Cloneable {
    private String name;
    private String company;
    //TODO get set方法
    
    public BusinessCard(){
        System.out.println("調(diào)用構(gòu)造方法");
    }
    
    public Object clone() throws CloneNotSupportException{
        return super.clone();
    }
    
    public void show() {
        System.out.println("name:"+name+",compnay:"+company);
    }    
}

//客戶端
public class Clinet {
    public static void main(String[] args) {
        BusinessCard businessCard = new BusinessCard();
        businessCard.setName("張三");
        businessCard.setCompany("百度");
        
        BusinessCard cloneCard1 = businessCard.clone();
        cloneCard1.setName("李四");
        cloneCard1.setCompany("阿里巴巴");
        
        BusinessCard cloneCard2 = businessCard.clone();
        cloneCard2.setName("王五");
        cloneCard2.setCompany("騰訊");
        
        businessCard.show();
        cloneCard1.show();
        cloneCard2.show();
    }
}


//對(duì)象類(lèi)型

public class Company {
    private String name;
    private String address;
    //TODO get set 方法
}
public class BusinessCard implements Cloneable {
    private String name;
    private Company company = new Company();
    //TODO get set 方法
    
    public BusinessCard(){
        System.out.println("初始化構(gòu)造方法");
    }
    
    public void setCompany(String name,String address){
        this.company.setName(name);
        this.company.setAddress(address);
    }
    
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    public void show(){  System.out.println("name:"+name+",compnayName:"+company.getName()+",compnayAddress:"+company.getAddress());
    }

}

//客戶端
public class Clinet {
    public static void main(String[] args) {
        BusinessCard businessCard = new BusinessCard();
        businessCard.setName("張三");
        businessCard.setCompany("百度", "西二旗");
        
        BusinessCard cloneCard1 = businessCard.clone();
        cloneCard1.setName("李四");
        cloneCard1.setCompany("聯(lián)想", "中關(guān)村");
        
        BusinessCard cloneCard2 = businessCard.clone();
        cloneCard2.setName("王五");
        cloneCard2.setCompany("騰訊", "望京");
        
        businessCard.show();
        cloneCard1.show();
        cloneCard2.show();
    }
}

//輸出結(jié)果company:全為 騰訊 望京

String是一種擁有值類(lèi)型特定的特殊引用類(lèi)型。
這是因?yàn)镺bject類(lèi)提供的clone方法,不會(huì)拷貝對(duì)象中的內(nèi)部數(shù)組和引用對(duì)象,導(dǎo)致它們?nèi)耘f指向原來(lái)對(duì)象的內(nèi)部元素地址,這種拷貝叫做淺拷貝

實(shí)現(xiàn)深拷貝:

//修改Company實(shí)現(xiàn)Cloneable接口,實(shí)現(xiàn)clone方法
public class Company implements Cloneable {
    private String name;
    private String address;
    //TODO get set 方法
    
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//修改BusinessCard的clone方法:
protected Object clone() throws CloneNotSupportedException {
    BusinessCard businessCard = null;
    businessCard = (BusinessCard)super.clone();
    businessCard.company = (Company)company.clone();
    return  businessCard;
}

原型設(shè)計(jì)模式的使用場(chǎng)景:

如果類(lèi)的初始化需要耗費(fèi)較多的資源,那么可以通過(guò)原型拷貝避免這些消耗。

通過(guò)new產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問(wèn)權(quán)限,則可以使用原型模式。

一個(gè)對(duì)象需要提供給其他對(duì)象訪問(wèn),而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以拷貝多個(gè)對(duì)象供調(diào)用者使用,即保護(hù)性拷貝。

優(yōu)點(diǎn):
原型模式是在內(nèi)存中二進(jìn)制流的拷貝,要比new一個(gè)對(duì)象的性能要好,特別是需要產(chǎn)生大量對(duì)象時(shí)
缺點(diǎn):
直接在內(nèi)存中拷貝,構(gòu)造函數(shù)是不會(huì)執(zhí)行的,這樣就減少了約束,這既是優(yōu)點(diǎn)也是缺點(diǎn),需要在實(shí)際應(yīng)用中去考量。

觀察者模式

定義:觀察者模式又叫發(fā)布-訂閱模式(Publish/Subscribe),定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新自己。
觀察者模式有兩種方模型,分別是推模型和拉模型

觀察者模式(Oberver)結(jié)構(gòu)圖:

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

抽象被觀察者角色:定義了動(dòng)態(tài)增加、刪除以及通知觀察者對(duì)象的方法,職責(zé)就是管理和通知觀察者。持有觀察者對(duì)象的集合。
具體被觀察者角色:一般繼承抽象被觀察者,實(shí)現(xiàn)自己本身的業(yè)務(wù)邏輯,當(dāng)狀態(tài)發(fā)生改變時(shí)發(fā)起通知。
抽象觀察者角色:提供一個(gè)接口,定義了觀察者收到通知時(shí)更新自己的方法。
具體觀察者角色:實(shí)現(xiàn)抽象觀察者接口,處理不同具體觀察者的不同業(yè)務(wù)邏輯。

//抽象被觀察者
public abstract class Subject {
    private List observerList = new ArrayList<>();
    
    public void attach(Observer observer){
        observerList.add(observer);
        System.out.println("增加了觀察者:"+observer.getName);
    }
    
    public void dettach(Observer observer){
        observerList.remove(observer);
        System.out.println("刪除了觀察者:"+observer.getName);
    }
    
    public void notifyObserver(){
        for( Observer observer: observerList) {
            observer.update("灰太狼要搞事情了");
        }
    }
}

//具體被觀察者
public class Wolf extends Subject {
    public void invade() {
        System.out.println("灰太狼:我要搞事情了");
        notifyObserver();
    }
}

//抽象觀察者
public interface Observer {
    String getName();
    void update(String msg);
}

//具體觀察者
public PleasantSheep implents Observer {
    public String getName() {
        return "喜洋洋";
    }
    
    public void update(String msg) {
        System.out.println("喜洋洋收到通知:"+msg);
    }   
}

public LazySheep implents Observer {
    public String getName() {
        return "懶洋洋";
    }
    
    public void update(String msg) {
        System.out.println("懶洋洋收到通知:"+msg);
    }   
}

//客戶端
public class Client {
    public static void main(String[] args) {
        //灰太狼--被觀察者
        Wolf wolf = new Wolf();
        
        //喜洋洋--觀察者
        Observer pleasantSheep= new PleasantSheep();
        //登記觀察者
        wolf.attach(pleasantSheep);
        
        // 懶羊羊--觀察者
        Observer lazySheep = new LazySheep();
        // 登記觀察者
        wolf.attach(lazySheep);
        
        //灰太狼入侵
        wolf.invade();
        
    }
}

JDK(被觀察者【Observable】和觀察者【Observer】)
在JAVA語(yǔ)言的 java.util 庫(kù)里面,提供了一個(gè)Observable類(lèi)以及一個(gè)Observer接口,構(gòu)成JAVA語(yǔ)言對(duì)觀察者模式的支持。

基于JDK實(shí)現(xiàn):

//被觀察者
public class Wolf extends Observable {
    private String message;
    //TODO
    
    public Wolf(){
        System.out.println("灰太狼:我要搞事情了!");
    }
    
    public void invade() {
         message="大灰狼來(lái)了!";
         super.setChanged();
         super.notifyObservers();
    }   
}

//觀察者
public class PleasantSheep implements Observer {
    public void update(Observable o,Object arg) {
        System.out.println("喜洋洋接到通知:"+((Wolf)o).getMessage());
    }
}

public class LazySheep implements Observer {
    public void update(Observable o,Object arg) {
        System.out.println("懶洋洋接到通知:"+((Wolf)o).getMessage());
    }
}

public class Client {
    public static void main(String[] args) {
        //被觀察者--灰太狼
        Wolf wolf = new Wolf();
        
        //觀察者--喜洋洋
        PleasantSheep pleasantSheep = new PleasantSheep();
        //登記觀察者
        wolf.addObserver(pleasantSheep);
        
        //觀察者--懶洋洋
        LazySheep lazySheep = new LazySheep();
        //登記觀察者
        wolf.addObserver(lazySheep);
        
        //灰太狼入侵
        wolf.invade();
    }
}

優(yōu)點(diǎn):
(1)觀察者和被觀察者之間抽象耦合。觀察者模式容易擴(kuò)展,被觀察者只持有觀察者集合,并不需要知道具體觀察者內(nèi)部的實(shí)現(xiàn)。
(2)對(duì)象之間的保持高度的協(xié)作。當(dāng)被觀察者發(fā)生變化時(shí),所有被觀察者都會(huì)通知到,然后做出相應(yīng)的動(dòng)作。
缺點(diǎn):
(1)如果觀察者太多,被觀察者通知觀察者消耗的時(shí)間很多,影響系統(tǒng)的性能。
(2)當(dāng)觀察者集合中的某一觀察者錯(cuò)誤時(shí)就會(huì)導(dǎo)致系統(tǒng)卡殼,因此一般會(huì)采用異步方式。
(3)抽象通知者還是依賴了抽象觀察者,當(dāng)沒(méi)有觀察者的時(shí)候,沒(méi)辦法更新。
(4)要求觀察者的所有動(dòng)作必須一樣 ,如果不一樣的話,不能實(shí)現(xiàn)。

事件委托
一次通知,執(zhí)行了不同類(lèi)的不同方法。
PS:Java中是沒(méi)有像c#delegate關(guān)鍵字的,所以我是通過(guò)用Java中的反射來(lái)實(shí)現(xiàn)。

適配器模式

定義:將一個(gè)類(lèi)的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類(lèi)可以一起工作。

適配器模式主要解決什么問(wèn)題?
需要的東西就在前面,但卻不能使用,而短時(shí)間內(nèi)又無(wú)法改造它,于是我們就想辦法試配它。
適配器模式主要應(yīng)用于希望復(fù)用一些現(xiàn)存的類(lèi),但是接口又與復(fù)用環(huán)境要求不一致的情況。

GOF設(shè)計(jì)模式中對(duì)適配器模式將了兩種類(lèi)型,類(lèi)適配器和對(duì)象適配器。
建議盡量使用對(duì)象的適配器模式,少用繼承。
何時(shí)使用適配器模式?
軟件開(kāi)發(fā)后期或維護(hù)期。
第三方開(kāi)發(fā)組件。
適配器模式屬于補(bǔ)償模式,專(zhuān)門(mén)用來(lái)在系統(tǒng)后期擴(kuò)展、修改時(shí)使用,但要注意不要過(guò)度使用適配器模式。

適配器模式(Adapter)結(jié)構(gòu)圖:

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

//球員
public abstract class Player {
    protected Sring name;
    public Player(String name){
        this.name = name;
    }
    public abstract void attack();
    public abstract void defense();
}

//前鋒
public Forward extends Player {
    public void attack() {
        Systme.out.println("前鋒"+name+"進(jìn)攻");
    }
    public void defense() {
        Systme.out.println("前鋒"+name+"防守");
    }
}
//中鋒
public Center extends Player {
    public void attack() {
        Systme.out.println("中鋒"+name+"進(jìn)攻");
    }
    public void defense() {
        Systme.out.println("中鋒"+name+"防守");
    }
}

...

//外籍中鋒
public class ForeignCenter {
    private String name;
    public void 進(jìn)攻(){
        Systme.out.println("外籍中鋒"+name+"進(jìn)攻");
    }
    public void 防守(){
        Systme.out.println("外籍中鋒"+name+"防守");
    }
}

//翻譯
public class Translator extends Player {
    private ForeignCenter foreignCenter = new ForeignCenter();
    public void attack() {
        foreignCenter.進(jìn)攻(); 
    }
    public void defense() {
        foreignCenter.防守();
    }
}
裝飾模式

定義:動(dòng)態(tài)地給一個(gè)對(duì)象增加一些額外的職責(zé),就增加功能來(lái)說(shuō),裝飾模式比生成子類(lèi)更為靈活。

外觀模式 建造者模式 狀態(tài)模式 享元模式 中介者模式

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68425.html

相關(guān)文章

  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹(shù)打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無(wú)意間聽(tīng)到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹(shù)打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • 一份送給Java初學(xué)者的指南

    摘要:編程思想第版這本書(shū)要常讀,初學(xué)者可以快速概覽,中等程序員可以深入看看,老鳥(niǎo)還可以用之回顧的體系。以下視頻整理自慕課網(wǎng)工程師路徑相關(guān)免費(fèi)課程。 我自己總結(jié)的Java學(xué)習(xí)的系統(tǒng)知識(shí)點(diǎn)以及面試問(wèn)題,目前已經(jīng)開(kāi)源,會(huì)一直完善下去,歡迎建議和指導(dǎo)歡迎Star: https://github.com/Snailclimb/Java-Guide 筆者建議初學(xué)者學(xué)習(xí)Java的方式:看書(shū)+視頻+實(shí)踐(初...

    banana_pi 評(píng)論0 收藏0
  • Java開(kāi)發(fā)

    摘要:大多數(shù)待遇豐厚的開(kāi)發(fā)職位都要求開(kāi)發(fā)者精通多線程技術(shù)并且有豐富的程序開(kāi)發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問(wèn)題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...

    LuDongWei 評(píng)論0 收藏0
  • 2018年總結(jié)

    摘要:一直想做一個(gè)總結(jié)吧,拖延癥,一直拖到了現(xiàn)在。設(shè)計(jì)模式在去年,月的時(shí)候,學(xué)習(xí)了大部分的設(shè)計(jì)模式。數(shù)據(jù)結(jié)構(gòu)和算法不是科班出身,所以找了一本算法書(shū),重頭到尾,認(rèn)真學(xué)習(xí)了一遍。學(xué)完感受就是,會(huì)寫(xiě)數(shù)據(jù)結(jié)構(gòu)和算法還是會(huì)寫(xiě),不會(huì)寫(xiě)的還是不會(huì)寫(xiě)。 工作了一年多了,這一年里,過(guò)的還是比較充實(shí)。一直想做一個(gè)總結(jié)吧,拖延癥,一直拖到了現(xiàn)在。 1 設(shè)計(jì)模式 在去年3,4月的時(shí)候,學(xué)習(xí)了大部分的設(shè)計(jì)模式。設(shè)計(jì)模...

    張漢慶 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<