適配器模式把一個類的接口變換成客戶端所期待的另外一種接口,使得本來因接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做。java
interface Target { void operation1(); void operation2(); } class Adaptee { public void operation1() {} } class Adapter extends Adaptee implements Target { @Override public void operation2() {} }
interface Target { void operation1(); void operation2(); } class Adaptee { public void operation1() {} } class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void operation1() { adaptee.operation1(); } @Override public void operation2() { // do something } }
// 充電器只能接受USB接口 public class Charger { public static void main(String[] args) throws Exception{ USB usb = new SuperAdapter(new TypeC()); connect(usb); usb = new SuperAdapter(new Lightning()); connect(usb); } public static void connect(USB usb) { usb.power(); usb.data(); } } // 充電器的接口都是USB的,假設有兩個方法分別是電源和數據 interface USB { void power(); void data(); } // IOS的Lightning接口 class Lightning { void iosPower() { System.out.println("IOS Power"); } void iosData() { System.out.println("IOS Data"); } } // TYPE-C接口 class TypeC { void typeCPower() { System.out.println("TypeC Power"); } void typeCData() { System.out.println("TypeC Data"); } } // 超級適配器,能夠適配多種手機機型 class SuperAdapter implements USB { private Object obj; public SuperAdapter(Object obj) { this.obj = obj; } @Override public void power() { if(obj.getClass() == Lightning.class) { ((Lightning)obj).iosPower(); } else if(obj.getClass() == TypeC.class) { ((TypeC)obj).typeCPower(); } } @Override public void data() { if(obj.getClass() == Lightning.class) { ((Lightning)obj).iosData(); } else if(obj.getClass() == TypeC.class) { ((TypeC)obj).typeCData(); } } }
缺省適配模式爲一個接口提供缺省實現,這樣子類型能夠從這個缺省實現進行擴展,而沒必要從原有接口進行擴展。ios
Monk
接口定義了兩個方法,因而它的子類必須實現這兩個方法。LuZhiShen
,他只能實現一部分方法,另外一部分方法沒法實現MonkAdapter
實現此Monk
接口,此抽象類給接口全部方法都提供一個空的方法,LuZhiShen
只須要繼承該適配類便可。// 和尚 interface Monk { void practiceKungfu(); void chantPrayer(); } abstract class MonkAdapter implements Monk { @Override public void practiceKungfu() {} @Override public void chantPrayer() {} } class LuZhiShen extends MonkAdapter { @Override public void practiceKungfu() { System.out.println("拳打鎮關西"); } }
缺省適配器模式可使所須要的類沒必要實現不須要的接口。數據庫
組合模式,就是在一個對象中包含其餘對象,這些被包含的對象多是終點對象(再也不包含別的對象),也有多是非終點對象(其內部還包含其餘對象)。
咱們將對象稱爲節點,即一個根節點包含許多子節點,這些子節點有的再也不包含子節點,而有的仍然包含子節點,以此類推。很明顯,這是樹形結構,終結點叫葉子節點,非終節點叫樹枝節點,第一個節點叫根節點。編程
安全式的合成模式要求管理集合的方法只出如今樹枝結點(Composite)中,而不出如今樹葉結點中。
設計模式
透明的合成模式要求全部的具體構建類,都符合一個固定的接口。安全
裝飾器模式(Decorator)容許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是做爲現有的類的一個包裝。ide
InputStream
ByteArrayInputStream
、PipedInputStream
、StringBufferInputStream
等原始流處理器。FilterInputStream
DateInputStream
、BufferedInputStream
、LineNumberInputStream
也用到類裝飾器模式this
// Component:一個藝人 interface Artist { void show(); } // Concrete Component:一個歌手 class Singer implements Artist { @Override public void show() { System.out.println("Let It Go"); } } // 裝飾後的歌手:不只會唱歌,還會講笑話和跳舞 class SuperSinger implements Artist { private Artist role; public SuperSinger(Artist role) { this.role = role; } @Override public void show() { System.out.println("Tell Jokes!"); role.show(); System.out.println("Dance!"); } }
代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象對引用。spa
public class Test { public static void main(String[] args) { Subject subject = new RealSubject(); Subject proxy = new ProxySubject(subject); proxy.request(); // 此處經過代理類來執行 } } interface Subject { void request(); } class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject"); } } class ProxySubject implements Subject { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } @Override public void request() { System.out.println("ProxySubject"); } }
自從JDK 1.3之後,Java在java.lang.reflect
庫中提供了一下三個類直接支持代理模式:Proxy
、InvocationHander
、Method
。設計
InvocationHandler
Proxy.newInstance()
invoke()
方法中執行相應操做public class Test { public static void main(String[] args) { // 建立要被代理的實例對象 Subject subject = new RealSubject(); // 建立一個與被代理實例對象有關的InvocationHandler InvocationHandler handler = new ProxySubject(subject); // 建立一個代理對象來代理subject,被代理的對象subject的每一個方法執行都會調用代理對象proxySubject的invoke方法 Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, handler); // 代理對象執行 proxySubject.request(); } } interface Subject { void request(); } class RealSubject implements Subject { @Override public void request() { System.out.println("RealSubject"); } } class ProxySubject implements InvocationHandler { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } /** * @param proxy 要代理的 * @param method * @param args * @return */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before Proxy"); Object obj = method.invoke(subject, args); System.out.println("After Proxy"); return obj; } }
ProxySubject
適配器模式的用意是改變所考慮對象的接口,而代理模式不能改變。
享元模式以共享的方式高效地支持大量的細粒度對象。
單純享元模式中,全部的享元對象都是能夠共享的。
內蘊狀態:是存儲在享元對象內部的,不會隨環境改變而改變的。一個享元能夠具備內蘊狀態並能夠共享。
外蘊狀態:隨環境改變而改變、不能夠共享的狀態。享元對象的外蘊狀態必須由客戶端保存,並在享元對象被建立以後,在須要使用的時候再傳入到享元對象內部。
享元模式中的對象不必定非要是不變對象,但大多數享元對象的確是這麼設計的。
減小對象的建立,下降內存消耗
依舊是熟悉的KFC點餐爲例:
public class KFC { public static void main(String[] args) { OrderFactory orderFactory = OrderFactory.getInstance(); Order order = orderFactory.getOrder(Food.MiniBurger); order.operation("李雷"); order = orderFactory.getOrder(Food.MiniBurger); order.operation("韓梅梅"); } } enum Food { MiniBurger, MexicanTwister, CornSalad, HotWing, PepsiCola } // Flyweight角色 interface Order { // 傳入的是外蘊對象:顧客 void operation(String customer); } // ConcreteFlyweight角色 class FoodOrder implements Order { // 內蘊狀態 private Food food; // 構造方法,傳入享元對象的內部狀態的數據 public FoodOrder(Food food) { this.food = food; } @Override public void operation(String customer) { System.out.println("顧客[" + customer + "]點的是" + food.toString()); } } // FlyweightFactory角色 class OrderFactory { private Map<Food, Order> orderPool = new HashMap<>(); private static OrderFactory instance = new OrderFactory(); private OrderFactory() {} public static OrderFactory getInstance() { return instance; } // 獲取Food對應的享元對象 public Order getOrder(Food food) { Order order = orderPool.get(food); if (null == order) { order = new FoodOrder(food); orderPool.put(food, order); } return order; } }
門面模式(Facade Pattern)要求一個子系統的外部與其內部通訊,必須經過一個統一的門面對象進行。
門面模式沒有一個通常化的類圖描述,能夠用下面的例子來講明。
一般只須要一個門面類,並且只有一個實例,所以能夠設計稱單例模式。固然也可有多個類。
MVC三層結構
假如沒有服務員(門面),顧客(外部系統)要點一個套餐須要知道每一個套餐包含的食物(子系統)種類,這樣就會很是麻煩,因此最好的方式是直接告訴服務員套餐名稱就行了。
public class Customer { public static void main(String[] args) { Waiter waiter = new Waiter(); List<Food> foodList = waiter.orderCombo("Combo1"); } } abstract class Food {} class MiniBurger extends Food {} class MexicanTwister extends Food {} class CornSalad extends Food {} class HotWing extends Food {} class PepsiCola extends Food {} class Waiter { public List<Food> orderCombo(String comboName) { List<Food> foodList; switch (comboName) { case "Combo1" : foodList = Arrays.asList(new MiniBurger(), new CornSalad(), new PepsiCola()); break; case "Combo2": foodList = Arrays.asList(new MexicanTwister(), new HotWing(), new PepsiCola()); break; default: foodList = new ArrayList<>(); } return foodList; } }
過濾器模式使用不一樣的條件過濾一組對象,並經過邏輯操做以解耦方式將其連接。這種類型的設計模式屬於結構模式,由於該模式組合多個標準以得到單個標準。
Java8中的lambda表達式能夠更簡單的實現過濾器
List<Movie> movies = Stream.of( new Movie("大話西遊","comedy"), new Movie("泰囧", "comedy"), new Movie("禁閉島", "suspense")) .filter(var -> "comedy".equals(var.getType())) .collect(Collectors.toList());
Movie
,根據它的type
屬性實現過濾Criteria
,規定過濾方法ComedyMovieCriteria
,根據comedy==movie.type
來過濾出須要的喜劇電影public class Test { public static void main(String[] args) { List<Movie> movies = new ArrayList(){{ add(new Movie("大話西遊","comedy")); add(new Movie("泰囧", "comedy")); add(new Movie("禁閉島", "suspense")); }}; System.out.println(new ComedyMovieCriteria().meetCriteria(movies)); } } // 被篩選的對象 class Movie { private String name; // 電影類型 private String type; public Movie(String name, String type) { this.name = name; this.type = type; } // getters & setters & toString } // 過濾器接口 interface Criteria { /** * @param movies 要被篩選的電影 * @return 篩選後的結果 */ List<Movie> meetCriteria(List<Movie> movies); } // 過濾喜劇電影的過濾器,要求是movie.type==comedy class ComedyMovieCriteria implements Criteria { @Override public List<Movie> meetCriteria(List<Movie> movies) { List<Movie> result = new ArrayList<>(); for (Movie movie : movies) { if ("comedy".equals(movie.getType())) { result.add(movie); } } return result; } }
橋接模式是將抽象化與實現化解耦,使二者能夠獨立地變化。橋接模式有助於理解面向對象的設計原則,包括開閉原則以及組合聚合複用原則。
抽象化:存在於多個實體中的共同的概念性聯繫;經過忽略一些信息,把不一樣的實體看成相同的實體來對待。
實現化:抽象化給出的具體實現就是實現化。一個類的實例就是這個類的實現化,一個子類就是它超類的實現化。
解耦:耦合就是兩個實體的某種強關聯,把它們的強關聯去掉就是解耦。
強關聯與弱關聯:所謂強關聯,就是在編譯期已經肯定的,沒法在運行期動態改變的關聯;所謂弱關聯,就是能夠動態地肯定而且能夠在運行期動態地改變的關聯。繼承是強關聯,而聚合關係是弱關聯。
橋接模式中的脫耦,就是在抽象化和實現化之間使用組合關係而不是繼承關係,從而使二者能夠相對獨立的變化。
大多數的驅動器(Driver)都是橋接模式的應用,使用驅動程序的應用系統就是抽象化角色,而驅動器自己扮演實現化角色。
SendMsg
及其子類是按照發送消息的方式進行擴展的;而Send
是按照發送消息的時間進行擴展的,二者互不影響。Send
持有類一個SendMsg
對象,並可使用此對象的方法。// Implementor角色 interface SendMsg { void sendMsg(); } // Concrete Implementor角色 class EmailSendMsg implements SendMsg { @Override public void sendMsg() { System.out.println("Send Msg By Email"); } } // Concrete Implementor角色 class WeChatSendMsg implements SendMsg { @Override public void sendMsg() { System.out.println("Send Msg By WeChat"); } } // Abstraction 角色 abstract class Send { protected SendMsg sendMsg; public Send(SendMsg sendMsg) { this.sendMsg = sendMsg; } public abstract void send(); } // Concrete Implementor角色 class ImmediatelySend extends Send { public ImmediatelySend(SendMsg sendMsg) { super(sendMsg); } @Override public void send() { sendMsg.sendMsg(); System.out.println("Send Msg Immediately"); } } // Concrete Implementor角色 class DelayedlySend extends Send { public DelayedlySend(SendMsg sendMsg) { super(sendMsg); } @Override public void send() { sendMsg.sendMsg(); System.out.println("Send Msg DelayedlySend"); } }