国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java設計模式學習總結

songze / 412人閱讀

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

前言

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

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

UML類圖


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

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

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

簡單工廠模式

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

簡單工廠模式結構圖:

//抽象產(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)想電腦啟動");
    }
}

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

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

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

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

面試題:請用C++,Java,C#,或VB.NET任意一種面向對象語言實現(xiàn)一個計算器控制臺程序,要求輸入兩個數(shù)和運算符號,得到結果。

活字印刷

易維護:要改,只需要改要改之字。

可復用:每個字在印刷中可重復使用。

易擴展:要加字,只需另刻字加入。

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

面向對象的分析設計編程思想:考慮通過封裝,繼承,多態(tài)把程序的耦合度降低,用設計模式使得程序更加靈活,容易修改,并且易于復用。
初級程序員的工作就是:Ctrl+C和Ctrl+V。
編程有一個原則:用盡可能的辦法避免重復。代碼重復到一定程度,維護就是一場災難。
復制粘貼是最容易的編程,也是最沒有價值的編程。

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

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

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

不能只滿足于寫完代碼運行結果正確就完事,時??紤]如何讓代碼更加簡練,更加容易維護,容易擴展和復用,只有這樣才可以真正得到提高。

工廠方法模式

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

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

通過反射實現(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)想電腦啟動");
    }
}

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

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

//抽象工廠
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;
    }
}

//客戶端調用
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();
    }
}

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

抽象工廠模式

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

抽象工廠(Abstract Factory)模式結構圖:

實現(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)想臺式機啟動");
    }
}

public HpDesktopComputer extends DesktopComputer {
    public void start(){
        System.out.println("惠普臺式機啟動");
    }
}

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

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

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

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

策略設計模式

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

面試題:請用任意面向對象語言,設計實現(xiàn)一個商場收銀功能,需包含:打折(9折,8折,五折),返現(xiàn)(滿300返100,滿100返50),及正常價格收費。

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

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

正常收費子類。

打折收費子類。

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

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

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

//打折收費子類
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)收費子類
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;
        }
    }  
}

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

    策略模式和簡單工廠模式結合,將客戶端條件判斷轉移到CashContext中。
    客戶端調用略

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

代理設計模式

代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。
為什么要有代理模式?
開閉原則,對擴展開放,對修改關閉。
為什么有靜態(tài)代理和動態(tài)代理?
最大的缺點:接口變化了,除了實現(xiàn)類需要改變,代理也需要修改。實際上我們是不想讓代理也需要修改的。所以出現(xiàn)了動態(tài)代理。
jdk 動態(tài)代理的缺點?
必須要實現(xiàn)接口。
jdk動態(tài)代理為什么必須要實現(xiàn)接口?
因為他默認繼承的proxy類,java是單繼承,所以必須要實現(xiàn)接口。
spring aop 最核心的思想:動態(tài)代理。
什么樣的場景下用cglib?
看代理的對象有沒有接口,沒有接口的用cglib。
代理模式使用場景
無法或者不想直接訪問某個對象時可以通過一個代理對象來間接的訪問。

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

//實現(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();
    
    //動態(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 ;
        }
    });    
}
單例設計模式

定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

餓漢式(線程安全)

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

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

懶漢式(線程不安全)

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

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

懶漢式(線程安全)

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

每次調用getInstance方法時都需要同步,造成不必要的同步開銷,大部分時候是用不到同步的,所以不建議使用這種模式。

雙重檢查枷鎖(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進行了兩次判空,第一次是為了不必要的同步,第二次是在singleton等于null的情況下才創(chuàng)建實例。
DCL雖然在一定程度解決了資源的消耗和多余的同步,線程安全等問題,但是他還是在某些情況會出現(xiàn)失效的問題,也就是DCL失效,在《java并發(fā)編程實踐》一書建議用靜態(tài)內部類單例模式來替代DCL。

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

枚舉

public enum Singleton {
    INSTANCE;
}

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

模板方法模式

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

原型設計模式

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

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

注意:Prototype通常是不用自己定義的,因為拷貝這個操作十分常用,Java中就提供了Cloneable接口來支持拷貝操作,它就是原型模式中的Prototype。當然,原型模式也未必非得去實現(xiàn)Cloneable接口,也有其他的實現(xiàn)方式。
Cloneable接口是一個標識接口,表示這個對象是可拷貝的,只要重寫clone方法就可以實現(xiàn)拷貝。clone方法不是在Cloneable接口中定義的(Cloneable接口中沒有定義任何方法),而是在Object中定義的。

//淺復制
public class BusinessCard implements Cloneable {
    private String name;
    private String company;
    //TODO get set方法
    
    public BusinessCard(){
        System.out.println("調用構造方法");
    }
    
    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("初始化構造方法");
    }
    
    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)想", "中關村");
        
        BusinessCard cloneCard2 = businessCard.clone();
        cloneCard2.setName("王五");
        cloneCard2.setCompany("騰訊", "望京");
        
        businessCard.show();
        cloneCard1.show();
        cloneCard2.show();
    }
}

//輸出結果company:全為 騰訊 望京

String是一種擁有值類型特定的特殊引用類型。
這是因為Object類提供的clone方法,不會拷貝對象中的內部數(shù)組和引用對象,導致它們仍舊指向原來對象的內部元素地址,這種拷貝叫做淺拷貝

實現(xiàn)深拷貝:

//修改Company實現(xiàn)Cloneable接口,實現(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;
}

原型設計模式的使用場景:

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

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

一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可以拷貝多個對象供調用者使用,即保護性拷貝。

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

觀察者模式

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

觀察者模式(Oberver)結構圖:

實現(xiàn):

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

//抽象被觀察者
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 庫里面,提供了一個Observable類以及一個Observer接口,構成JAVA語言對觀察者模式的支持。

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

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

適配器模式

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

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

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

適配器模式(Adapter)結構圖:

實現(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+"進攻");
    }
    public void defense() {
        Systme.out.println("前鋒"+name+"防守");
    }
}
//中鋒
public Center extends Player {
    public void attack() {
        Systme.out.println("中鋒"+name+"進攻");
    }
    public void defense() {
        Systme.out.println("中鋒"+name+"防守");
    }
}

...

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

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

定義:動態(tài)地給一個對象增加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。

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

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68425.html

相關文章

  • Java學習路線總結,搬磚工逆襲Java架構師(全網(wǎng)最強)

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

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

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

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

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

    LuDongWei 評論0 收藏0
  • 2018年總結

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

    張漢慶 評論0 收藏0

發(fā)表評論

0條評論

songze

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<