摘要:適配器模式不應(yīng)在設(shè)計階段考慮,它是為了解決已經(jīng)上線的問題的存在。組合模式將對象組合成樹形結(jié)構(gòu)以表示部分整體的層次結(jié)構(gòu),使得用戶對單個對象和組合對象的使用具有一致性。
代理模式
代理模式之前已經(jīng)講過,附上鏈接代理模式
裝飾者模式裝飾者模式定義:動態(tài)地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
裝飾模式博主在第一次學習是懵逼的,是因為代理模式中代理對象和目標對象都實現(xiàn)了同一個接口,裝飾者模式中裝飾對象和被裝飾對象也都實現(xiàn)了同一個接口,并且都可以很容易的在方法前面或后面增加一些功能來達到增強方法的目的。其實裝飾模式就是代理模式的一個特殊應(yīng)用,兩者的共同點是都實現(xiàn)了同一個接口,不同點就是代理模式著重對代理過程的控制,而裝飾模式是對類的功能進行增強或減弱,它著重類的功能變化。
java的規(guī)范必然是jdk源碼了,學習裝飾者模式一定要看下io的實現(xiàn)。io是負責讀取數(shù)據(jù)的,而數(shù)據(jù)的來源又分為文件、字節(jié)數(shù)組、字符緩沖區(qū)、線程輸入流、序列化的對象等等。如下圖所示:
圖有點丑....輸入流讀取數(shù)據(jù)按照數(shù)據(jù)來源已經(jīng)分成五類,按理來說應(yīng)該夠用了,那為什么還會有BufferedInputStream,DataInputStream,PushbackInputStream呢?我們拿bufferinputstream來分析,因為io流讀取是訪問硬盤,硬盤的訪問速度在計算機的世界里一定是極慢的,也是極其耗資源的,為了解決這個問題,發(fā)明了BufferedInputStream,先讀取buffer,實在找不到再去硬盤里找。那我們怎么將其加入到io家族中呢?如果我們給每種io流增加子類,使其擁有讀取buffer的能力,那么僅以圖中展示出來的,就要加5個子類,加上DataInputStream(byte轉(zhuǎn)成java數(shù)據(jù)類型),PushbackInputStream(讀取之后寫回流)那就是15個子類,已經(jīng)形成了類爆炸的問題,任誰看到都是頭大的...
加入我們需要一個既可以讀buffer又可以將數(shù)據(jù)轉(zhuǎn)成java類型的輸入流,正確的姿勢是這樣的:
//InputStream inputStream = new BufferedInputStream(new DataInputStream(new FileInputStream(""))); BufferedInputStream inputStream = new BufferedInputStream(new DataInputStream(new FileInputStream("")));
從這里就可以看出來裝飾者模式和依賴倒置原則是有點沖突的,因為依賴倒置原則讓我們依賴抽象,說白了就是面向接口編程,如果我們面向接口使用InputStream聲明,它依然無法擁有緩存的能力,這證明了想要找出一段完全符合六大設(shè)計模式的代碼是很難的...
適配器模式將一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠一起工作。
適配器模式最好在設(shè)計階段不要考慮它,他不是為了解決開發(fā)階段存在的問題,而是解決已經(jīng)上線的項目問題。任何一個架構(gòu)師都不應(yīng)該在設(shè)計階段考慮使用適配器模式,并且項目一定要嚴格遵守依賴倒置原則和里氏替換原則,適配器模式才會帶給你巨大的好處,否則即使在適合用適配器模式的情況下,也會給項目帶來巨大改造。
現(xiàn)在假設(shè)這樣一個場景,A公司收購了B公司,要對B公司的用戶數(shù)據(jù)和項目進行一個內(nèi)部消化,但兩個系統(tǒng)的實現(xiàn)又不一樣,如何最小的改動最優(yōu)的整合到一起呢?我們拿用戶模塊來看下,A公司的用戶是這樣設(shè)計的:
public interface IUserInfo { String getName(); String getSex(); void getMobile(); }
public class UserInfo implements IUserInfo { @Override public String getName() { System.out.println("老子是光頭強"); } @Override public String getSex() { System.out.println("老子是男性"); } @Override public String getMobile() { System.out.println("手機號:12345678"); } }
B公司用戶模塊是這樣設(shè)計的:
public interface IUserDetail { Map getUserBaseinfo(); }
public class UserDetail implements IUserDetail { private Map map; @Override public Map getUserBaseinfo() { map = new HashMap(); map.put("name","張三"); map.put("sex","男"); map.put("phone","1896369448"); return null; } }
首先我們的系統(tǒng)要和他們的系統(tǒng)進行交互,不可能為了這一小小的功能對我們已經(jīng)良好運行的項目進行大改動,那怎么辦呢?只能轉(zhuǎn)化了,拿到對方的數(shù)據(jù)對象然后轉(zhuǎn)化為我們自己的數(shù)據(jù)對象。設(shè)計是這樣子的:
public class NewUser extends UserDetail implements IUserInfo { @Override public String getName() { String name = (String) super.getUserBaseinfo().get("name"); System.out.println(name); return name; } @Override public String getSex() { return (String) super.getUserBaseinfo().get("sex"); } @Override public String getMobile() { return (String) super.getUserBaseinfo().get("mobile"); } }
測試類是這樣的:
//大boss獲取A公司人員的手機號,臨時反悔想要B公司人員的手機號 public class Client { // public static void main(String[] args) { //IUserInfo userInfo = new UserInfo(); //userInfo.getMobile(); //} public static void main(String[] args) { //臨時改變主意獲取B公司人員的手機號 IUserInfo userInfo1 = new NewUser(); userInfo1.getMobile(); } }
使用適配器模式只修改了一句話,其他的業(yè)務(wù)邏輯不用修改就既覺了對接的問題。適配器可以讓兩個沒有任何關(guān)系的類在一起運行,只要適配器這個角色能搞定他們就行。適用適配器模式的場景只要記住一點就夠了:當你要去修改一個已經(jīng)投入到生產(chǎn)當中的接口,適配器模式可能是最適合你的模式了。適配器模式不應(yīng)在設(shè)計階段考慮,它是為了解決已經(jīng)上線的問題的存在。
門面模式要求一個子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個統(tǒng)一的對象進行。門面模式提供一個高層次的接口,使得子系統(tǒng)更易于使用。
門面模式注重統(tǒng)一的對象,提供一個訪問子系統(tǒng)的接口,除了這個接口不允許有任何訪問子系統(tǒng)的行為發(fā)生。門面對象是外界訪問子系統(tǒng)內(nèi)部的唯一通道,不管子系統(tǒng)內(nèi)部多么雜亂無章,只要門面對象在,就可以做到"金玉其外,敗絮其中"。
源碼中應(yīng)用此模式的非常多,slf4j使用的就是此模式。這是一個簡單的設(shè)計模式,直接給大家上例子:
public interface Drink { void drink(); }
public class Milk implements Drink { @Override public void drink() { System.out.println("喝牛奶"); } }
public class RedTea implements Drink { @Override public void drink() { System.out.println("喝紅茶"); } }
public class Water implements Drink { @Override public void drink() { System.out.println("喝涼白開"); } }
public class Facade { private Milk milk = new Milk(); private RedTea redTea = new RedTea(); private Water water = new Water(); public void drinkMilk(){ milk.drink(); } public void drinkRedTea(){ redTea.drink(); } public void drinkWater(){ water.drink(); } }
統(tǒng)一的對象指的就是門面,也就是上述例子中的facade。
門面模式可以減少系統(tǒng)間的互相依賴,因為所有的依賴都是依賴于門面對象,與子系統(tǒng)的業(yè)務(wù)無關(guān)。只依賴門面對象,也就是說子系統(tǒng)的業(yè)務(wù)如何變化只要不影響到門面對象,大大提高了靈活性。缺點就是過于依賴門面對象,不符合開閉原則,一旦門面對象中出現(xiàn)錯誤,對子系統(tǒng)的打擊是非常大的,修改門面對象時,一定要慎之又慎。
將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),使得用戶對單個對象和組合對象的使用具有一致性。
概念有點抽象,但其實很簡單。相信大部分猿都用過,只是不知道他還有這個名字罷了。簡單的模式不啰嗦,直接上例子:
public class Person { private String name; private String age; private Listlist = new ArrayList<>(); public void addPerson(){ list.add(new Person()); } public void removePerson(Person person){ list.remove(person); } public Person getChild(int i){ return list.get(i); } }
每個人都有年齡和姓名,每個人也都會有孩子。構(gòu)造成樹形結(jié)構(gòu),使單個對象和組合對象的訪問具有一致性。模式很簡單,不浪費大家時間。
享元模式使用共享對象可有效的支持大量的細粒度的對象。
享元模式是池技術(shù)實現(xiàn)的核心思想。其核心概念有共享對象和細粒度的對象.細粒度的對象的特點就是對象數(shù)量多切性質(zhì)相近,我們應(yīng)將其不變的部分抽出來形成共享對象,存放在池中,減少內(nèi)存使用.復用對象最簡單的方式是,用一個 HashMap 來存放每次新生成的對象。每次需要一個對象的時候,先到 HashMap 中看看有沒有,如果沒有,再生成新的對象,然后將這個對象放入 HashMap 中.代碼很簡單,不在舉例.
橋梁模式將抽象和實現(xiàn)解耦,使得兩者可以獨立的變化。
橋梁模式的關(guān)鍵點在于解耦。現(xiàn)在的公司有很多,我們今天拿互聯(lián)網(wǎng)公司和外包公司來舉例。每個公司會有很多部門,每個部門工作的方式又不一樣,模式很簡單,直接上例子:
//抽象部門接口,用來定義要實現(xiàn)的方法 public interface IDepartment { //每個部門都要工作,公司請你不是來吃閑飯的 void work(); }
//苦逼的程序員 public class Coder implements IDepartment { @Override public void work() { System.out.println("程序猿工作:將咖啡變成代碼"); } }
//苦逼的測試 public class QA implements IDepartment { @Override public void work() { System.out.println("測試:保證產(chǎn)品質(zhì)量"); } }
//it公司 public abstract class ITCompany { //引入部門抽象 private IDepartment iDepartment; public ITCompany(IDepartment iDepartment) { this.iDepartment = iDepartment; } public void work(){ iDepartment.work(); } } //互聯(lián)網(wǎng)公司 class InternetCompany extends ITCompany{ public InternetCompany(IDepartment iDepartment) { super(iDepartment); } } //外包公司 class outerPackCompany extends ITCompany{ public outerPackCompany(IDepartment iDepartment) { super(iDepartment); } }
public class Client { public static void main(String[] args) { ITCompany itCompany = new InternetCompany(new Coder()); itCompany.work(); ITCompany outerPackCompany = new outerPackCompany(new QA()); outerPackCompany.work(); } }
怎么樣,很簡單把。它的重點就是解耦,符合開閉原則和依賴倒置原則。在此架構(gòu)的基礎(chǔ)上,我們不管是想要增加抽象還是具體實現(xiàn)類都是易如反掌。橋梁模式的意圖就是對變化的封裝,把可能變化的封裝到最小的邏輯單元,避免風險擴散.
總結(jié)設(shè)計模式到此就算告一段落了。學習設(shè)計模式可以有助于我們寫出優(yōu)雅、易維護、易擴展的代碼,也可以讓我們更好的理解源碼。為了寫設(shè)計模式的文章,看了兩三本關(guān)于設(shè)計模式的書,翻閱了許多資料,講的不是特別好,但總歸可以帶大家入門。若是大家想看書學習,按照難度從低到高可自行選擇:<大話設(shè)計模式>、<設(shè)計模式之禪>、gof的<設(shè)計模式>.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68380.html
面試舊敵之紅黑樹(直白介紹深入理解) - Android - 掘金 讀完本文你將了解到: 什么是紅黑樹 黑色高度 紅黑樹的 5 個特性 紅黑樹的左旋右旋 指定節(jié)點 x 的左旋 右圖轉(zhuǎn)成左圖 指定節(jié)點 y 的右旋左圖轉(zhuǎn)成右圖 紅黑樹的平衡插入 二叉查找樹的插入 插入后調(diào)整紅黑樹結(jié)構(gòu) 調(diào)整思想 插入染紅后... java 多線程同步以及線程間通信詳解 & 消費者生產(chǎn)者模式 & 死鎖 & Thread...
摘要:新的數(shù)據(jù)表關(guān)系數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)類似于這樣子大碼中碼小碼這個表結(jié)構(gòu)的說明是避免對于關(guān)系鏈的數(shù)據(jù)邏輯不理解做的一個示例。 最近幾天一直在糾結(jié)于一個大數(shù)據(jù)批量導入的問題,經(jīng)過幾天思考,發(fā)現(xiàn)基于小數(shù)據(jù)情況,原本的數(shù)據(jù)結(jié)構(gòu)設(shè)計是沒有問題的,但是在大量數(shù)據(jù)導入,問題就很大了。我之前一直在強調(diào)程序=數(shù)據(jù)結(jié)構(gòu)+算法,但在這此卻鉆了牛角尖,最后去仔細看了之前別人設(shè)計的數(shù)據(jù)表才突然靈光一現(xiàn),發(fā)現(xiàn)了mysql...
摘要:可以說,如果問題是我們的敵人,代碼是我們的劍,設(shè)計模式就是高手心中的劍譜。中級選手,在編程的時候知道何時該用什么設(shè)計模式,而什么時候不該用。設(shè)計模式被用來簡化設(shè)計,讓設(shè)計更優(yōu)雅。其中最具有普遍性的方案往往就是我們的設(shè)計模式的內(nèi)容。 showImg(https://segmentfault.com/img/remote/1460000019100076?w=800&h=440); 目錄概...
閱讀 2068·2021-11-24 09:39
閱讀 774·2021-09-30 09:48
閱讀 974·2021-09-22 15:29
閱讀 2410·2019-08-30 14:17
閱讀 1885·2019-08-30 13:50
閱讀 1336·2019-08-30 13:47
閱讀 978·2019-08-30 13:19
閱讀 3418·2019-08-29 16:43