亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

songze / 505人閱讀

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

前言

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

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

UML類圖


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

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

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

簡單工廠模式

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

簡單工廠模式結(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)");
    }
}

//工廠類
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();
    }
}

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

活字印刷

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

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

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

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

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

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

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("請輸入一個(gè)數(shù)字A:");
    double numberA = scanner.nextDouble();
    System.out.println("請輸入一個(gè)運(yùn)算符(+,-,*,/):");
    String oper = scanner.next();
    System.out.println("請輸入一個(gè)數(shù)字B:");
    double numberB = scanner.nextDouble();
    Operate operate = OperateFactory.createOperate(oper);
    operate.setNumberA(numberA);
    operate.setNumberB(numberB);
    System.out.println(operate.getResult());   
}

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

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

工廠方法模式

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

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

通過反射實(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í)都沒有修改的變化,而只是擴(kuò)展的變化,這就完全符合了開放-封閉原則。
工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來實(shí)現(xiàn)運(yùn)算類,工廠方法把簡單工廠的內(nèi)部邏輯判斷轉(zhuǎn)移到了客戶端代碼來進(jìn)行。

抽象工廠模式

定義:提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定他們具體的類。
當(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)滿足不了需求,可用抽象工廠模式來解決。

抽象工廠(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):
具體類的創(chuàng)建實(shí)例過程與客戶端分離,客戶端通過工廠的抽象接口操縱實(shí)例,客戶端并不知道具體的實(shí)現(xiàn)是誰。
缺點(diǎn):
如果增加新的產(chǎn)品族則也需要修改抽象工廠和所有的具體工廠。

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

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

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

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

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

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

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

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

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

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

//打折收費(fè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)子類
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è)對Strategy對象的引用
public class CashContext {
    private CashSuper cashSuper;
    
    public CashContext (CashSuper cashSuper) {
        this.cashSuper = cashSuper;
    }
    
    public double getResult(double money){
        return cashSuper.acceptCash(money);
    }  
}

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

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

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

代理模式(Proxy),為其他對象提供一種代理以控制對這個(gè)對象的訪問。
為什么要有代理模式?
開閉原則,對擴(kuò)展開放,對修改關(guān)閉。
為什么有靜態(tài)代理和動(dòng)態(tài)代理?
最大的缺點(diǎn):接口變化了,除了實(shí)現(xiàn)類需要改變,代理也需要修改。實(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類,java是單繼承,所以必須要實(shí)現(xiàn)接口。
spring aop 最核心的思想:動(dòng)態(tài)代理。
什么樣的場景下用cglib?
看代理的對象有沒有接口,沒有接口的用cglib。
代理模式使用場景
無法或者不想直接訪問某個(gè)對象時(shí)可以通過一個(gè)代理對象來間接的訪問。

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

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

//代理類
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("操作后");
    }
}

//測試
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è)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。

餓漢式(線程安全)

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

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

懶漢式(線程不安全)

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í)都需要同步,造成不必要的同步開銷,大部分時(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;
    } 
}

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

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

枚舉

public enum Singleton {
    INSTANCE;
}

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

模板方法模式

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

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

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

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

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


//對象類型

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是一種擁有值類型特定的特殊引用類型。
這是因?yàn)镺bject類提供的clone方法,不會(huì)拷貝對象中的內(nèi)部數(shù)組和引用對象,導(dǎo)致它們?nèi)耘f指向原來對象的內(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ì)模式的使用場景:

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

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

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

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

觀察者模式

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

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

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

抽象被觀察者角色:定義了動(dòng)態(tài)增加、刪除以及通知觀察者對象的方法,職責(zé)就是管理和通知觀察者。持有觀察者對象的集合。
具體被觀察者角色:一般繼承抽象被觀察者,實(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語言的 java.util 庫里面,提供了一個(gè)Observable類以及一個(gè)Observer接口,構(gòu)成JAVA語言對觀察者模式的支持。

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

//被觀察者
public class Wolf extends Observable {
    private String message;
    //TODO
    
    public Wolf(){
        System.out.println("灰太狼:我要搞事情了!");
    }
    
    public void invade() {
         message="大灰狼來了!";
         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)對象之間的保持高度的協(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)沒有觀察者的時(shí)候,沒辦法更新。
(4)要求觀察者的所有動(dòng)作必須一樣 ,如果不一樣的話,不能實(shí)現(xiàn)。

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

適配器模式

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

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

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

適配器模式(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è)對象增加一些額外的職責(zé),就增加功能來說,裝飾模式比生成子類更為靈活。

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

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/68425.html

相關(guān)文章

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

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

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

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

    banana_pi 評論0 收藏0
  • Java開發(fā)

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

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

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

    張漢慶 評論0 收藏0

發(fā)表評論

0條評論

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