分类:
创建型模式(关注对象的创建过程):
单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
结构型模式(关注对象和类的组织):
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
行为型模式(关注对象之间的交互,研究运行时对象之间的通信协作):
模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、
策略模式、职责链模式、访问者模式。
1,适配器模式(adapter):
概念:
将一个类的接口转换成客户希望的另一个接口,使不兼容转换为可以一起工作。
角色:
- 目标接口(Target):客户期待的接口。
- 需要适配的类(Adaptee):提供给适配器的类。
- 适配器(Adapter): 通过包装一个需要适配的对象,把原接口转换成目标接口。
使用场景:
经常用来做旧系统改造和升级,开发新的模块并且以适配器的模式来兼容旧系统时的模块。
常用的类有: java.io.InputStreamReader(InputStream),java.io.InputStreamWriter(OutputStream)
适配器模式实现:
举个例子:
比如 iphone7手机没有 耳机插孔 如果想用 有线耳机 则需要一个 转换器 来适配手机充电口和耳机插口。
1,类适配器方法:
1、 /** * 被适配对象(如图中:耳机) */ public class Adaptee { public void request(){ System.out.println("可以完成客户需要的功能。。。"); } } 2、 /** * 适配接口 */ public interface Target { void handlerReq(); } 3、 /** * 适配器类( 如图中:转换器) */ public class Adapter extends Adaptee implements Target{ public void handlerReq() { super.request(); } } 4、 /** * 调用者(如图中:手机) */ class Client { //测试方法 public void test(Target t) { t.handlerReq(); } //执行 public static void main(String[] args) { // 整个流程: 调用者去 接入 适配器,适配器去 接入 被适配对象 Client c = new Client(); c.test(new Adapter()); } }
2,对象适配器方法:
1、 /** * 被适配对象(如图中:耳机) */ public class Adaptee { public void request(){ System.out.println("可以完成客户需要的功能。。。"); } } 2、 /** * 适配接口 */ public interface Target { void handlerReq(); } 3、 /** * 适配器类( 如图中:转换器) */ public class Adapter implements Target{ public Adaptee adaptee; public Adapter(Adaptee adaptee){ super(); this.adaptee = adaptee; } public void handlerReq() { adaptee.request(); } } 4、 /** * 调用者(如图中:手机) */ class Client { //测试方法 public void test(Target t) { t.handlerReq(); } //执行 public static void main(String[] args) { // 整个流程: 调用者去 接入 适配器,适配器去 接入 被适配对象 Client c = new Client(); c.test(new Adapter(new Adaptee())); } }
2,代理模式(Proxy pattern):
概念:
通过代理,控制对对象的访问,控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。AOP(面向切面编程)的核心实现就是代理模式。
角色:
- 抽象角色:定义代理角色和真实角色的公共对外方法。
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务方法来实现抽象方法,并可以附加自己的操 作。
使用场景:
- 安全代理:屏蔽对真实角色的直接访问。
- 远程代理:通过代理类处理远程方法的调用(RMI)。
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
分类:
- 静态代理:代理类由手动自己创建。
- 动态代理: 由程序自动生成代理方法。(JDK自带动态代理,javaassist字节码操作库实现,CGLIB...)
代理对象实现:
1,静态代理:
1、 public interface Star { //面谈 void confer(); //签合同 void bookTicket(); //唱歌 void sing(); //收钱 void collectMoney(); } 2、 /** * 真实角色 */ public class RealStar implements Star { public void confer() { System.out.println("真实:RealStar.confer()"); } public void bookTicket() { System.out.println("真实:RealStar.bookTicket()"); } public void sing() { System.out.println("真实:RealStar.sing()"); } public void collectMoney() { System.out.println("真实:RealStar.collectMoney()"); } } 3、 /** * 代理对象 */ public class ProxyStar implements Star { private Star realStar; public ProxyStar(Star realStar) { this.realStar = realStar; } public void confer() { System.out.println("代理:ProxyStar.confer()"); } public void bookTicket() { System.out.println("代理:ProxyStar.bookTicket()"); } public void sing() { // TODO 需求:代理对象需要执行真实角色中的 sing() 方法 realStar.sing(); } public void collectMoney() { System.out.println("代理:ProxyStar.collectMoney()"); } public static void main(String[] args) { //真实角色 Star realStar = new RealStar(); //代理角色 Star proxyStar = new ProxyStar(realStar); //以代理对象方式,执行真实角色中的 sing() 方法 proxyStar.sing(); } }
2,动态代理:
JDK自带动态代理:
- java.lang.reflect.Proxy:动态生成代理类和对象(每次生成的代理类对象都要指定对应的处理器对象)
- java.lang.reflect.InvocationHandler:可通过invoke方法实现对真实对象代理访问。
1、 public interface Star { //面谈 void confer(); //签合同 void bookTicket(); //唱歌 void sing(); //收钱 void collectMoney(); } 2、 /** * 真实角色 */ public class RealStar implements Star { public void confer() { System.out.println("真实:RealStar.confer()"); } public void bookTicket() { System.out.println("真实:RealStar.bookTicket()"); } public void sing() { System.out.println("真实:RealStar.sing()"); } public void collectMoney() { System.out.println("真实:RealStar.collectMoney()"); } } 3、 public class StarHandler implements InvocationHandler { private Star realStar; public StarHandler(Star realStar) { this.realStar = realStar; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //执行你调用的方法 System.out.println("######方法开始#####"); method.invoke(realStar ,args); System.out.println("######方法结束#####"); return null; } public static void main(String[] args){ //代理处理类 StarHandler proxyHandler = new StarHandler(new RealStar()); //动态生成 代理角色 Star proxy = (Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class},proxyHandler); proxy.confer(); proxy.sing(); System.out.println(); } }
动态代理开发场景:
- Struts2 中拦截器的实现
- 数据库连接池关闭处理
- Mybatis实现拦截器插件
- Spring中的AOP的实现(日志拦截,声明式事务)
- RMI远程方法调用
3,组合模式(composite):
概念:
把部分和整体的关系用树形结构来标识,从而使客户端可以使用同一的方式处理部分对象和整体对象。
(主要是为了处理树形结构而应用的模式。)
组合模式核心:
- 抽象构件(Component):定义了叶子和容易构件的共同点。
- 叶子构件(Leaf):无子节点。
- 容器构件:有容器特征,可以包含子节点。
应用场景:
- GUI中的容器层次图。
- XML文件解析。
- Junit单元测试框架。(底层设计就是组合模式)
举例实现:
1、 //抽象构件 public interface AbstractFile { void recursion(); //递归打印 } class VideoFile implements AbstractFile { private String name; public VideoFile(String name) { this.name = name; } public void recursion() { System.out.println("--视频文件:"+name+"---"); } } class ImageFile implements AbstractFile { private String name; public ImageFile(String name) { this.name = name; } public void recursion() { System.out.println("--图像文件:"+name+"---"); } } class Folder implements AbstractFile{ private String name; private List<AbstractFile> list = new ArrayList<AbstractFile>(); public Folder(String name) { this.name = name; } public void add(AbstractFile file){ list.add(file); } public void remove(AbstractFile file){ list.remove(file); } public void getChild(int index){ list.get(index); } //递归方法实现 public void recursion() { System.out.println("--文件夹:"+name+"---"); for (AbstractFile file : list) { file.recursion(); } } } 2、 public class Client { public static void main(String[] args) { Folder f1 = new Folder("我的收藏"); f1.add(new ImageFile("大胖的肌肉.jpg") { }); f1.add(new VideoFile("大胖和国家的二三事.AVI")); //将 我的收藏2 文件夹存入 大胖的肌肉实在不得了.jpg和大胖和宇宙的二三事.AVI //再把 我的收藏2 放入 我的收藏 中 Folder f11 = new Folder("我的收藏2"); f11.add(new ImageFile("大胖的肌肉实在不得了.jpg") { }); f11.add(new VideoFile("大胖和宇宙的二三事.AVI")); f1.add(f11); f1.recursion(); System.out.println(); } }
4,装饰器模式(decorator):
概念:
也叫包装器模式(Wrapper),动态的为一个对象增加或删除对象的功能,是一种代替继承的技术。无需通过继承增加子类就能扩展对象的新功能。
(比如 一个屋子(相当于:new的对象),可对这个屋子 装灯具,壁纸等一系列的装饰便是装饰器模式)
优点:
使用装饰模式灵活的使对象的关联关系代替了继承关系,避免类与类之间的继承关系过于复杂。
缺点:
产生很多小对象,大量小对象占据内存,影响性能。并且易于出错,调试排查麻烦。
组件核心:
- Component 抽象构件角色: 真实对象和装饰对象相同的接口,这样客户端对象就能以真实对象相同的方式同装饰对象交互。
- ConcreteComponent 具体构件角色(真实对象): io流中的FileInputStream,FileOutputStream
- Decorator装饰器角色: 先实现 抽象构件角色,让所有调用者请求转发给真实的对象。
- ConcreteDecorator具体装饰角色: 负责给构件对象增加新的责任。
举例实现:
1、 /** * 抽象组件 */ public interface ICar { void move(); } // ConcreteComponent 具体构件角色(真实对象) class Car implements ICar{ public void move() { System.out.println("汽车在陆地上跑!"); } } // 装饰器角色 class SuperCar implements ICar{ private ICar car; public SuperCar(ICar car) { this.car = car; } public void move() { car.move(); } } //为真实对象提供的装饰品(ConcreteDecorator具体装饰角色) class FlyCar extends SuperCar{ public FlyCar(ICar car) { super(car); } public void fly(){ System.out.println("为 Car 添加飞行功能"); } @Override public void move() { super.move(); fly(); } } //为真实对象提供的装饰品(ConcreteDecorator具体装饰角色) class WaterCar extends SuperCar{ public WaterCar(ICar car) { super(car); } public void water(){ System.out.println("为 Car 添加水上游功能"); } @Override public void move() { super.move(); water(); } } //为真实对象提供的装饰品(ConcreteDecorator具体装饰角色) class AICar extends SuperCar{ public AICar(ICar car) { super(car); } public void AI(){ System.out.println("为 Car 添加智能功能"); } @Override public void move() { super.move(); AI(); } } 2、 public class Test { public static void main(String[] args){ System.out.println("【为添加装饰前:】"); Car c =new Car(); c.move(); System.out.println(); //添加单个装饰品 System.out.println("【添加飞行功能:】"); FlyCar flyCar = new FlyCar(c); flyCar.move(); System.out.println(); //添加多个装饰品 System.out.println("【添加飞行 , 水上游 , 智能 功能:】"); AICar aiCar = new AICar(new WaterCar(new FlyCar(c))); aiCar.move(); } }
概略图:
使用场景:
- IO中的输入流和输出流设计。
- Servlet API中提供了一个request对象的Decorator设计模式的默认实现类 HttpServletRequestWrapper、HttpServletRequestWrapper类,增加了request对象的功能。
5,外观模式:
核心:
其实就是封装对象,为调用者提供便携的入口,减少调用者调用时的复杂性。
举例实现:
比如:如果没有汽车商家的话,想购车需要联系厂家买车,联系银行上车险,跑去税务局交税之类的...外观模式的核心就是把繁琐的步骤封装起来,只提供汽车商家供用户购买汽车,其他事宜全都代办。
public class Merchant{ public void BugCar(){ AutoMakers autoMakers = new AutoMakers(); autoMakers.getCar(); Bank bank = new Bank(); bank.insurance(); TheRevenue theRevenue = new TheRevenue(); theRevenue.tax(); } } class AutoMakers { public void getCar(){ System.out.println("从厂家获取汽车"); } } class Bank{ public void insurance(){ System.out.println("为汽车上保险"); } } class TheRevenue{ public void tax(){ System.out.println("为汽车交税"); } } class Client{ public static void main(String[] args){ Merchant merchant =new Merchant(); merchant.BugCar(); } }
6,享元模式(FlyWeight):
概念:
将完全相同或者相似的对象,通过享元模式共享,节省内存空间。
核心:
- 以共享的方式高效的支持大量细粒度对象的重用。享元对象能做到共享的关键是区分了内部状态和外部状态。
- 内部状态:对象的内部属性,数据,占用空间大小都相同。
- 外部状态:对象在内存空间中的地址不同。
核心组件:
- FlyWeightFactory享元工厂类: 创建并管理享元对象,享元池一般设计成键值对。
- FlyWeight抽象享元类: 通常是接口或者抽象类,声明公共方法,这些方法向外界提供对象的内部状态,设置外部状态。
- ConcreateFlyWeight具体享元类:为内部状态提供成员变量进行存储。
- UnsharedConcreateFlyWeight非共享享元类:不能被共享的子类可以设计为非共享享元类。
应用场景:
- 由于享元模式共享的特征,常用在线程池,数据库连接池等...
- String类的设计也是享元模式。
优缺点:
- 优点:减少内存中对象数量,相同或相似对象内存中只存一份,提高性能,外部状态相对独立不影响内部状态。
- 缺点:模式较复杂,由于分离出 内部 外部状态,造成读取外部状态使运行时间变长。
举例实现:
1、 /** * 享元类 */ public interface ChessFlyWeight { void setColor(String color); String getColor(); void display(Coordinate c); } class ConcreteChess implements ChessFlyWeight { private String color; public ConcreteChess(String color) { this.color = color; } public void setColor(String color) { this.color = color; } public String getColor() { return color; } public void display(Coordinate c) { System.out.println("颜色:" + color); System.out.println("棋子位置:" + c.getX() + "-----" + c.getY()); } } 2、 /** * 外部状态UnsharedConcreateFlyWeight */ public class Coordinate { private int x,y; public Coordinate(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } 3、 /** * 享元工厂类 */ public class ChessFlyWeightFactory { private static Map<String , ChessFlyWeight> map = new HashMap<String , ChessFlyWeight>(); public static ChessFlyWeight getChess(String color){ if (map.get(color)!= null){ return map.get(color); }else{ ChessFlyWeight cfw = new ConcreteChess(color); map.put(color , cfw); return cfw; } } public static void main(String[] args){ ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色"); ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色"); System.out.println(chess1); System.out.println(chess2); System.out.println("增加外部状态处理(自定义棋子位置)====="); chess1.display(new Coordinate(10,10)); chess2.display(new Coordinate(20,20)); } }