适配器模式把一个类的接口变换成客户端所期待的另外一种接口,使得本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做。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"); } }