JAVA設(shè)計模式

一栓霜、設(shè)計模式的分類

什么是設(shè)計模式:在某些場景下翠桦,針對某類問題的某種通用的解決方案
特點: 通用、可復用

設(shè)計模式有哪些

  • 創(chuàng)建型模式 :對象實例化的模式胳蛮,用于解耦對象的實例化過程销凑。5種
    工廠方法模式、抽象工廠模式仅炊、單例模式斗幼、建造者模式、原型模式
  • 結(jié)構(gòu)型模式 :把類或?qū)ο蠼Y(jié)合在一起形成一個更大的結(jié)構(gòu)茂洒。7種
    適配器模式孟岛、裝飾器模式、代理模式督勺、外觀模式渠羞、橋接模式、組合模式智哀、享元模式
  • 行為型模式 : 類與對象交互次询,責任劃分及算法。11種
    策略模式瓷叫、模板方法模式屯吊、觀察者模式、迭代子模式摹菠、責任鏈模式盒卸、命令模式、備忘錄模式次氨、狀態(tài)模式蔽介、訪問者模式、中介者模式煮寡、解釋器模式
    共23種
  • 額外兩種: 并發(fā)型模式, 線程池模式

二虹蓄、設(shè)計模式的六大原則

總原則:開閉原則(Open Close Principle)
對擴展開放,對修改關(guān)閉幸撕。使程序的擴展性好锥咸,易于維護和升級, 使用接口和抽象類等, 實現(xiàn)熱插拔效果约啊。

1、單一職責原則
每個類應該實現(xiàn)單一的職責,解耦锌妻。

2、里氏替換原則(Liskov Substitution Principle)
對“開-閉”原則的補充序六,對實現(xiàn)抽象化的具體步驟的規(guī)范糕非。
子類對父類的方法盡量不要重寫和重載。因為父類代表了定義好的結(jié)構(gòu)站叼,通過這個規(guī)范的接口與外界交互娃兽,子類不應該隨便破壞它。

3尽楔、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)
開閉原則的基礎(chǔ)投储,面向接口編程,依賴于抽象而不依賴于具體阔馋。寫代碼時用到具體類時玛荞,不與具體類交互,而與具體類的上層接口交互呕寝。

4勋眯、接口隔離原則(Interface Segregation Principle)
每個接口中不存在子類用不到卻必須實現(xiàn)的方法,如果不然,就要將接口拆分客蹋。使用多個隔離的接口塞蹭,比使用單個接口(多個接口方法集合到一個的接口)要好。

5讶坯、迪米特法則(最少知道原則)(Demeter Principle)
一個類對自己依賴的類知道的越少越好番电。無論被依賴的類多么復雜,都應將邏輯封裝在方法的內(nèi)部辆琅,通過public方法提供給外部漱办。這樣當被依賴的類變化時,才能最小的影響該類婉烟。

6娩井、合成復用原則(Composite Reuse Principle)
盡量首先使用聚合的方式,而不是使用繼承


常見模式介紹

1) 單例模式

它核心結(jié)構(gòu)只包含一個被稱為單例類的特殊類似袁。通過單例模式可以保證系統(tǒng)中一個類只有一個實例而且該實例易于外界訪問撞牢,從而方便對實例個數(shù)的控制并節(jié)約系統(tǒng)資源。

應用場景:如果希望在系統(tǒng)中某個類的對象只能存在一個叔营,單例模式是最好的解決方案屋彪。

懶漢式

class LazyMan{

    private static LazyMan lm;
    private LazyMan(){};
    
    public static LazyMan getInstance(){
        if (lm == null){
            synchronized (LazyMan.class) {
                if (lm == null) {
                    lm = new LazyMan();
                }
            }
        }
        return lm;
    }
}

餓漢式

class HungeryMan{

    private static HungeryMan hm;
    
    private HungeryMan(){
        hm = new HungeryMan();
    };
    
    public static HungeryMan getInstance(){
        return hm;
    }
}
2) 工廠方法模式

工廠模式主要是為創(chuàng)建對象提供了接口。
應用場景:
a绒尊、 在編碼時不能預見需要創(chuàng)建哪種類的實例畜挥。
b、 系統(tǒng)不應依賴于產(chǎn)品類實例如何被創(chuàng)建婴谱、組合和表達的細節(jié)蟹但。

簡單工廠模式不屬于23種設(shè)計模式范疇。
簡單工廠模式的問題:類的創(chuàng)建依賴工廠類谭羔,若想要拓展程序华糖,必須對工廠類進行修改,這違背了閉包原則瘟裸,所以客叉,就有了工廠方法模式,創(chuàng)建一個工廠接口和創(chuàng)建多個工廠實現(xiàn)類话告,一旦需要增加新的功能兼搏,直接增加新的工廠類,不需要修改之前的代碼沙郭。

一個頂級接口

public interface Sender {  

    public void Send();  
}  

兩個實現(xiàn)類:

public class MailSender implements Sender {  

    @Override  
    public void Send() {  
        System.out.println("this is mailsender!");  
    }  
}  

public class SmsSender implements Sender {  

    @Override  
    public void Send() {  
        System.out.println("this is sms sender!");  
    }  
}  

兩個工廠類:

public class SendMailFactory implements Provider {  
      
    @Override  
    public Sender produce(){  
        return new MailSender();  
    }  
}  
[java] view plaincopy
public class SendSmsFactory implements Provider{  
  
    @Override  
    public Sender produce() {  
        return new SmsSender();  
    }  
}  

再提供一個接口:

public interface Provider {  
    public Sender produce();  
}  

測試類:

public class Test {  
  
    public static void main(String[] args) {  
        Provider provider = new SendMailFactory();  
        Sender sender = provider.produce();  
        sender.Send();  
    }  
}  
3) 策略模式

定義了算法族佛呻,分別封裝起來,讓它們之間可以互相替換病线。此模式讓算法的變化獨立于使用算法的客戶吓著。

應用場景:
a鲤嫡、 一件事情,有很多方案可以實現(xiàn)绑莺。
b泛范、我可以在任何時候,決定采用哪一種實現(xiàn)紊撕。
c.、未來可能增加更多的方案赡突。
d对扶、 策略模式讓方案的變化不會影響到使用方案的客戶。

策略模式的決定權(quán)在用戶惭缰,系統(tǒng)本身提供不同算法的實現(xiàn)浪南,新增或者刪除算法,對各種算法做封裝漱受。因此络凿,策略模式多用在算法決策系統(tǒng)中,外部用戶只需要決定用哪個算法即可昂羡。

需要設(shè)計一個接口絮记,為一系列實現(xiàn)類提供統(tǒng)一的方法,多個實現(xiàn)類實現(xiàn)該接口虐先≡狗撸可以設(shè)計一個抽象類(輔助類可有可無),提供輔助函數(shù)

首先統(tǒng)一接口:

public interface ICalculator {  

    public int calculate(String exp);  
}  

輔助類:

public abstract class AbstractCalculator {  
      
    public int[] split(String exp,String opt){  

        String array[] = exp.split(opt);  
        int arrayInt[] = new int[2];  
        arrayInt[0] = Integer.parseInt(array[0]);  
        arrayInt[1] = Integer.parseInt(array[1]);  
        return arrayInt;  
    }  
}  

三個實現(xiàn)類:

public class Plus extends AbstractCalculator implements ICalculator {  
  
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"\\+");  
        return arrayInt[0]+arrayInt[1];  
    }  
}  

public class Minus extends AbstractCalculator implements ICalculator {  
  
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"-");  
        return arrayInt[0]-arrayInt[1];  
    }  
  
}  

public class Multiply extends AbstractCalculator implements ICalculator {  
  
    @Override  
    public int calculate(String exp) {  
        int arrayInt[] = split(exp,"\\*");  
        return arrayInt[0]*arrayInt[1];  
    }  
} 

簡單的測試類:

public class StrategyTest {  
  
    public static void main(String[] args) {  
        String exp = "2+8";  
        ICalculator cal = new Plus();  
        int result = cal.calculate(exp);  
        System.out.println(result);  
    }  
}  

輸出:10

4) 觀察者模式蛹批。

又被稱作發(fā)布/訂閱模式撰洗,定義了對象間一對多依賴,當一個對象改變狀態(tài)時腐芍,它的所有依賴者都會收到通知并自動更新差导。

應用場景:
a、對一個對象狀態(tài)的更新猪勇,需要其他對象同步更新设褐,而且其他對象的數(shù)量動態(tài)可變。
b泣刹、對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節(jié)络断。

一個Observer接口:

public interface Observer {  

    public void update();  
}  

兩個實現(xiàn)類:

public class Observer1 implements Observer {  
  
    @Override  
    public void update() {  
        System.out.println("observer1 has received!");  
    }  
}  

public class Observer2 implements Observer {  
  
    @Override  
    public void update() {  
        System.out.println("observer2 has received!");  
    }  
}  

Subject接口及實現(xiàn)類:

public interface Subject {  
      
    /*增加觀察者*/  
    public void add(Observer observer);  
      
    /*刪除觀察者*/  
    public void del(Observer observer);  
      
    /*通知所有的觀察者*/  
    public void notifyObservers();  
      
    /*自身的操作*/  
    public void operation();  
}  

public abstract class AbstractSubject implements Subject {  
  
    private Vector<Observer> vector = new Vector<Observer>();  

    @Override  
    public void add(Observer observer) {  
        vector.add(observer);  
    }  
  
    @Override  
    public void del(Observer observer) {  
        vector.remove(observer);  
    }  
  
    @Override  
    public void notifyObservers() {  
        Enumeration<Observer> enumo = vector.elements();  
        while(enumo.hasMoreElements()){  
            enumo.nextElement().update();  
        }  
    }  
}  

public class MySubject extends AbstractSubject {  
  
    @Override  
    public void operation() {  
        System.out.println("update self!");  
        notifyObservers();  
    }  
  
}  

測試類:

public class ObserverTest {  
  
    public static void main(String[] args) {  

        Subject sub = new MySubject();  
        sub.add(new Observer1());  
        sub.add(new Observer2());  
          
        sub.operation();  
    }  
}  

輸出:
update self!
observer1 has received!
observer2 has received!

5) 裝飾器模式

給一個對象增加一些新的功能,而且是動態(tài)的项玛,要求裝飾對象和被裝飾對象實現(xiàn)同一個接口貌笨,裝飾對象持有被裝飾對象的實例

應用場景:
a、需要擴展一個類的功能襟沮。
b锥惋、動態(tài)的為一個對象增加昌腰、撤銷功能。(繼承的功能是靜態(tài)的膀跌,不能動態(tài)增刪遭商。)
缺點:產(chǎn)生過多相似的對象,不易排錯

接口

public interface Sourceable {  

    public void method();  
}  

原始實現(xiàn)類

public class Source implements Sourceable {  
  
    @Override  
    public void method() {  
        System.out.println("the original method!");  
    }  
}  

代理類

public class Decorator implements Sourceable {  
  
    private Sourceable source;  
      
    public Decorator(Sourceable source){  
        super();  
        this.source = source;  
    }  

    @Override  
    public void method() {  
        System.out.println("before decorator!");   //裝飾器
        source.method();  
        System.out.println("after decorator!");  //裝飾器
    }  
}  

測試類:

public class DecoratorTest {  
  
    public static void main(String[] args) {  

        Sourceable source = new Source();  
        Sourceable obj = new Decorator(source);  
        obj.method();  
    }  
}  

輸出:
before decorator!
the original method!
after decorator!

6) 代理模式

給一個對象提供一個代理捅伤,并由代理對象控制對原對象的引用劫流。它使得客戶不能直接與真正的目標對象通信。
代理對象是目標對象的代表丛忆,其他需要與這個目標對象打交道的操作都是和這個代理對象在交涉祠汇,起到中介的作用,既保護了目標對象的熄诡,同時也在一定程度上面減少了系統(tǒng)的耦合度可很。

應用場景:
如果已有的方法在使用的時候需要對原有的方法進行改進,此時有兩種辦法:
a凰浮、修改原有的方法來適應我抠。這樣違反了“對擴展開放,對修改關(guān)閉”的原則袜茧。
b菜拓、采用一個代理類調(diào)用原有的方法,對產(chǎn)生的結(jié)果進行控制笛厦。
使用代理模式尘惧,可以將功能劃分的更加清晰,有助于后期維護

接口

public interface Sourceable {  

    public void method();  
}  

原始實現(xiàn)類

public class Source implements Sourceable {  
  
    @Override  
    public void method() {  
        System.out.println("the original method!");  
    }  
}  

代理類

public class Proxy implements Sourceable {  
  
    private Source source;  

    public Proxy(){  
        super();  
        this.source = new Source();  
    }  

    @Override  
    public void method() {  
        before();  
        source.method();  
        atfer();  
    }  
    private void atfer() {  
        System.out.println("after proxy!");  
    }  
    private void before() {  
        System.out.println("before proxy!");  
    }  
}  

測試類:

public class ProxyTest {  
  
    public static void main(String[] args) {  

        Sourceable source = new Proxy();  
        source.method();  
    }  
}  

輸出:
before proxy!
the original method!
after proxy!

代理模式递递,偏重因自己無法完成或自己無需關(guān)心喷橙,需要他人干涉事件流程,更多的是對對象的控制登舞。
裝飾模式贰逾,偏重對原對象功能的擴展,擴展后的對象仍是是對象本身菠秒。

7) 迭代子模式疙剑。

提供一種方法順序訪問一個聚合對象中各個元素,而又不暴露該對象的內(nèi)部表示践叠。

應用場景:
當你需要訪問一個聚集對象言缤,而且不管這些對象是什么都需要遍歷的時候,就應該考慮用迭代器模式禁灼。其實stl容器就是很好的迭代器模式的例子管挟。

兩個接口

public interface Collection {  
      
    public Iterator iterator();  
      
    /*取得集合元素*/  
    public Object get(int i);  
      
    /*取得集合大小*/  
    public int size();  
}  
public interface Iterator {  
    //前移  
    public Object previous();  
      
    //后移  
    public Object next();  
    public boolean hasNext();  
      
    //取得第一個元素  
    public Object first();  
}  

兩個實現(xiàn):

public class MyCollection implements Collection {  
  
    public String string[] = {"A","B","C","D","E"};  

    @Override  
    public Iterator iterator() {  
        return new MyIterator(this);  
    }  
  
    @Override  
    public Object get(int i) {  
        return string[i];  
    }  
  
    @Override  
    public int size() {  
        return string.length;  
    }  
}  
public class MyIterator implements Iterator {  
  
    private Collection collection;  
    private int pos = -1;  
      
    public MyIterator(Collection collection){  
        this.collection = collection;  
    }  
      
    @Override  
    public Object previous() {  
        if(pos > 0){  
            pos--;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public Object next() {  
        if(pos<collection.size()-1){  
            pos++;  
        }  
        return collection.get(pos);  
    }  
  
    @Override  
    public boolean hasNext() {  
        if(pos<collection.size()-1){  
            return true;  
        }else{  
            return false;  
        }  
    }  
  
    @Override  
    public Object first() {  
        pos = 0;  
        return collection.get(pos);  
    }  
  
}  

測試類:

public class Test {  
  
    public static void main(String[] args) {  

        Collection collection = new MyCollection();  
        Iterator it = collection.iterator();  
          
        while(it.hasNext()){  
            System.out.println(it.next());  
        }  
    }  
}  

輸出:A B C D E

8) 模板方法模式

定義一個操作中的算法的骨架,將一些步驟延遲到子類中弄捕,模板方法使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些步驟僻孝。

應用場景:
對于一些功能导帝,在不同的對象身上展示不同的作用,但是功能的框架是一樣的穿铆。

public abstract class AbstractCalculator {  
      
    /*主方法您单,實現(xiàn)對本類其它方法的調(diào)用*/  
    public final int calculate(String exp,String opt){  
        int array[] = split(exp,opt);  
        return calculate(array[0],array[1]);  
    }  
      
    /*被子類重寫的方法*/  
    abstract public int calculate(int num1,int num2);  
      
    public int[] split(String exp,String opt){  
        String array[] = exp.split(opt);  
        int arrayInt[] = new int[2];  
        arrayInt[0] = Integer.parseInt(array[0]);  
        arrayInt[1] = Integer.parseInt(array[1]);  
        return arrayInt;  
    }  
}  
public class Plus extends AbstractCalculator {  
  
    @Override  
    public int calculate(int num1,int num2) {  
        return num1 + num2;  
    }  
}  

測試類:

public class StrategyTest {  
  
    public static void main(String[] args) {  
        String exp = "8+8";  
        AbstractCalculator cal = new Plus();  
        int result = cal.calculate(exp, "\\+");  
        System.out.println(result);  
    }  
}  

輸出:10

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市荞雏,隨后出現(xiàn)的幾起案子虐秦,更是在濱河造成了極大的恐慌,老刑警劉巖凤优,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悦陋,死亡現(xiàn)場離奇詭異,居然都是意外死亡别洪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門柳刮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挖垛,“玉大人,你說我怎么就攤上這事秉颗×《荆” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵蚕甥,是天一觀的道長哪替。 經(jīng)常有香客問我,道長菇怀,這世上最難降的妖魔是什么凭舶? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮爱沟,結(jié)果婚禮上帅霜,老公的妹妹穿的比我還像新娘。我一直安慰自己呼伸,他們只是感情好身冀,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著括享,像睡著了一般搂根。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铃辖,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天剩愧,我揣著相機與錄音,去河邊找鬼娇斩。 笑死隙咸,一個胖子當著我的面吹牛沐悦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播五督,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼藏否,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了充包?” 一聲冷哼從身側(cè)響起副签,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎基矮,沒想到半個月后淆储,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡家浇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年本砰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钢悲。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡点额,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莺琳,到底是詐尸還是另有隱情还棱,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布惭等,位于F島的核電站珍手,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辞做。R本人自食惡果不足惜琳要,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秤茅。 院中可真熱鬧焙蹭,春花似錦、人聲如沸嫂伞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帖努。三九已至撰豺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拼余,已是汗流浹背污桦。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留匙监,地道東北人凡橱。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓小作,卻偏偏與公主長得像,于是被迫代替她去往敵國和親稼钩。 傳聞我的和親對象是個殘疾皇子顾稀,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 面試被人問到了設(shè)計模式,發(fā)現(xiàn)這方面知識漏洞還非常大坝撑,所以在這里記錄備忘一下静秆。原文:https://blog.csd...
    onlyHalfSoul閱讀 491評論 0 2
  • 極客學院-23 種設(shè)計模式 Java之美[從菜鳥到高手演變]之設(shè)計模式Java之美[從菜鳥到高手演變]之設(shè)計模式 ...
    John13閱讀 2,837評論 0 0
  • 前言 1、設(shè)計模式來源巡李?答:設(shè)計模式來自于建筑領(lǐng)域抚笔,作為軟件工程的一個分支。1995年由GOF收集整理了23種設(shè)計...
    斌林誠上閱讀 5,151評論 1 13
  • 昨天聽福凱說,他已經(jīng)把前端項目由vuejs換成了react,因為鄧鵬問了福凱一些頁面上的事,估計就是這樣就提到了....
    再見田園犬閱讀 391評論 0 0
  • 每天學點銷售學——連續(xù)第132天 傾聽在溝通中有著很重要的作用膨蛮,作為銷售人員,更需要把傾聽這門藝術(shù)運用好矫夯。 所謂傾...
    今天的面包閱讀 319評論 0 1