JAVA的23种设计模式详解
一.介绍
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
二.二十三种设计模式
1.创建型模式:
关注对象的创建过程
作用:创建型模式帮助创建对象,
单例模式
作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
优点:由于单例模式只生成一个实例,减少了系统性能开销
常见的五种实现模式:
-
饿汉式(线程安全,调用效率高,但是,不能延时加载)
package com.singleton; /** * 测试饿汉式单例模式 * * Created by 拂晓 on 2019/7/22:21:56 */ public class SingletonDemol { //类加载时立即初始化(没有延时加载的优势) 天然的线程安全 private static final SingletonDemol instance = new SingletonDemol(); private SingletonDemol(){ } //方法没有同步,调用效率高 public static SingletonDemol getInstance(){ return instance; } }
-
懒汉式(线程安全,调用效率低,但是可以延时加载)
package com.singleton; /** * * 懒汉式单例模式 * * Created by 拂晓 on 2019/7/22:22:03 */ public class SingletonDemo2 { //类加载时,不初始化这个对象,(延时加载,真正用的时候再创建) private static SingletonDemo2 instance; //私有化构造器 private SingletonDemo2() { } //方法同步,调用效率低 public static synchronized SingletonDemo2 getInstance() { if (instance == null) { instance = new SingletonDemo2(); } return instance; } }
-
双重检测锁模式(提高了执行的效率,不必每次获取对象都同步,只有第一次才同步,创建以后就没必要了)
package com.singleton; /** * * 双重检测锁实现单例模式 * * Created by 拂晓 on 2019/7/22:22:03 */ public class SingletonDemo3 { //类加载时,不初始化这个对象,(延时加载,真正用的时候再创建) private static SingletonDemo3 instance = null; //私有化构造器 private SingletonDemo3() { } //方法同步,将同步内容下放到if内部 public static synchronized SingletonDemo3 getInstance() { if (instance == null) { SingletonDemo3 sc ; synchronized (SingletonDemo3.class){ sc = instance; if (sc == null){ synchronized (SingletonDemo3.class){ if(sc == null){ sc = new SingletonDemo3(); } } instance = sc ; } } } return instance; } } package com.singleton; /** * * 测试双重检测锁单例模式 * Created by 拂晓 on 2019/7/22:22:41 */ public class Client { public static void main(String[] args) { SingletonDemo3 s1 = SingletonDemo3.getInstance(); SingletonDemo3 s2 = SingletonDemo3.getInstance(); System.out.println(s1); System.out.println(s2); } }
-
静态内部类(线程安全,也是一种懒加载)
package com.singleton; /** * * 静态内部类实现单例模式 * 这种方式,线程安全,并且调用效率高,并且实现了延时加载 * Created by 拂晓 on 2019/7/22:22:03 */ public class SingletonDemo4 { //构造方法私有 private SingletonDemo4(){ } //定义静态内部类 private static class SingletonClassInstance{ private static final SingletonDemo4 instance =new SingletonDemo4(); } //方法没有私有同步,效率高 public static SingletonDemo4 getInstance(){ return SingletonClassInstance.instance; } } package com.singleton; /** * * 测试静态内部类实现单例模式 * Created by 拂晓 on 2019/7/22:22:41 */ public class Client { public static void main(String[] args) { SingletonDemo4 s1 = SingletonDemo4.getInstance(); SingletonDemo4 s2 = SingletonDemo4.getInstance(); System.out.println(s1); System.out.println(s2); } }
-
枚举模式(天然单例,没有延时加载)
package com.singleton; /** * * 枚举类实现单例模式 * * 避免了反射和反序列化的漏洞,调用效率比较高,但是没有延时加载 * Created by 拂晓 on 2019/7/22:22:03 */ public enum SingletonDemo5 { //这个枚举元素,本身就是单例对象 INSTANCE; //添加需要的操作 public void singletonOperation(){ } } package com.singleton; /** * * 测试枚举单例模式 * Created by 拂晓 on 2019/7/22:22:41 */ public class Client { public static void main(String[] args) { //枚举的方式 System.out.println(SingletonDemo5.INSTANCE==SingletonDemo5.INSTANCE); 结果为:true } }
如何选用?
-
单例对象 占用资源少,不需要延时加载
枚举式 好于 饿汉式
-
单例对象 占用资源大,需要延时加载
静态内部类 好于 懒汉式
-
工厂模式
作用:实现创建者和调用者的分离
详细分类:
-
简单工厂模式(生产同一等级结构中的任意产品,对于增加的新产品,需要修改已有代码,违反了开闭原则)
//创建接口Car public interface Car { void run(); } //创建2个实现类 public class Audi implements Car { @Override public void run() { System.out.println("奥迪在跑"); } } public class Byd implements Car { @Override public void run() { System.out.println("比亚迪在跑"); } } //创建简单工厂类的2种实现 //第一种 public class CarFactory1 { public static Car createCar(String type) { if ("奥迪".equals(type)) { return new Audi(); } else if ("比亚迪".equals(type)) { return new Byd(); } else { return null; } } } //第二种 public class CarFactory2 { public static Car createAudi() { return new Audi(); } public static Car createByd() { return new Byd(); } } package com.simplefactory; /** * 简单工厂模式的情况下 * * Created by 拂晓 on 2019/7/23:21:56 */ public class Client02 { //调用者 public static void main(String[] args) { Car c1 =CarFactory1.createCar("奥迪"); Car c2 =CarFactory1.createCar("比亚迪"); c1.run(); c2.run(); } }
-
工厂方法模式(解决了简单工厂不满足开闭原则的缺点)
//创建接口Car public interface Car { void run(); } //创建2个实现类 public class Audi implements Car { @Override public void run() { System.out.println("奥迪在跑"); } } public class Byd implements Car { @Override public void run() { System.out.println("比亚迪在跑"); } } //创建一个Car的工厂接口 public interface CarFactory { Car createCar(); } //分别创建Byd和AUdi的工厂类实现Car的工厂 public class AudiFactory implements CarFactory{ @Override public Car createCar() { return new Audi(); } } public class BydFactory implements CarFactory{ @Override public Car createCar() { return new Byd(); } } package com.methodfactory; /** * * 测试方法工厂 * Created by 拂晓 on 2019/7/23:22:21 */ public class Client { public static void main(String[] args) { Car c1 = new AudiFactory().createCar(); Car c2 = new BydFactory().createCar(); Car c3 = new BenzFactory().createCar(); c1.run(); c2.run(); c3.run(); } }
结构复杂度:简单工厂比方法工厂简单
代码复杂度:简单工厂比方法工厂简单
管理上的难度:工厂方法虽然遵循了开闭原则但是类多了,管理起来更复杂了
-
抽象工厂模式(生产不同产品族的全部产品)
package com.abstractfactory; /** * Created by 拂晓 on 2019/7/25:21:58 */ //发动机 public interface Engine { void run(); void start(); } //高端发动机的实现 class LuxuryEngine implements Engine{ @Override public void run() { System.out.println("跑的快"); } @Override public void start() { System.out.println("启动快"); } } //低端发动机的实现 class LowEngine implements Engine{ @Override public void run() { System.out.println("跑的慢"); } @Override public void start() { System.out.println("启动慢"); } } package com.abstractfactory; /** * Created by 拂晓 on 2019/7/25:22:00 */ //座椅 public interface Seat { void massage(); } //高端座椅的实现 class LuxurySeat implements Seat{ @Override public void massage() { System.out.println("自动按摩"); } } //低端座椅的实现 class LowSeat implements Seat{ @Override public void massage() { System.out.println("不能按摩"); } } package com.baizhi.abstractfactory; /** * Created by 拂晓 on 2019/7/25:22:02 */ //轮胎 public interface Tyre { void revolve(); } //高端轮胎的实现 class LuxuryTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损慢"); } } //低端轮胎的实现 class LowTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损快"); } } package com.baizhi.abstractfactory; /** * Created by 拂晓 on 2019/7/25:22:04 */ //生产汽车产品族的抽象工厂接口 public interface CarFactory { Engine createEngine(); Seat createSeat(); Tyre createTyre(); } package com.abstractfactory; /** * Created by 拂晓 on 2019/7/25:22:09 */ //生产低端产品族的汽车工厂实现 public class LowCarFactory implements CarFactory { @Override public Engine createEngine() { return new LowEngine(); } @Override public Seat createSeat() { return new LowSeat(); } @Override public Tyre createTyre() { return new LowTyre(); } } package com.abstractfactory; /** * Created by 拂晓 on 2019/7/25:22:06 */ //生产高端汽车产品族的工厂实现 public class LuxuryCarFactory implements CarFactory { @Override public Engine createEngine() { return new LuxuryEngine(); } @Override public Seat createSeat() { return new LuxurySeat(); } @Override public Tyre createTyre() { return new LuxuryTyre() ; } } package com.abstractfactory; /** * * 测试抽象工厂模式 * Created by 拂晓 on 2019/7/25:22:11 */ public class Client { public static void main(String[] args) { LuxuryCarFactory factory = new LuxuryCarFactory(); Engine engine = factory.createEngine(); engine.run(); engine.start(); } }
总结:简单工厂虽然不符合开闭原则,但是用的最多,方法工厂比简单工厂结构复杂
抽象工厂不可以增加产品,可以增加产品族 用的比较少;
应用场景:JDBC中Connection对象的获取,Hibernate中的SessionFactory创建Session ,Spring中IOC容器创建管理bean对象,反射中Class对象的newInstance();
建造者模式
作用:用来创造复杂对象,需要和工厂模式配合使用
package com.builder;
/**
*
* 宇宙飞船类
* Created by 拂晓 on 2019/7/26:20:01
*/
public class AirShip {
private OrbitalModule orbitalModule;//轨道舱
private Engine engine;//发动机
private EscapeTower escapeTower;//逃生舱
public void Launch(){
System.out.println("发射");
}
public OrbitalModule getOrbitalModule() {
return orbitalModule;
}
public void setOrbitalModule(OrbitalModule orbitalModule) {
this.orbitalModule = orbitalModule;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public EscapeTower getEscapeTower() {
return escapeTower;
}
public void setEscapeTower(EscapeTower escapeTower) {
this.escapeTower = escapeTower;
}
}
class OrbitalModule{
private String name;
public OrbitalModule(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public OrbitalModule() {
}
}
class Engine {
private String name;
public Engine(String name) {
this.name = name;
}
public String getName() {
return name="发动机";
}
public void setName(String name) {
this.name = name;
}
public Engine() {
}
}
class EscapeTower{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public EscapeTower(String name) {
this.name = name;
}
public EscapeTower() {
}
}
package com.builder;
/**
*
* 构造宇宙飞船需要的子件接口
*
* Created by 拂晓 on 2019/7/26:20:13
*/
public interface AirShipBuilder {
OrbitalModule builderOrbitalModule();
Engine builderEngine();
EscapeTower builderEscapeTower();
}
package com.builder;
/**
* 实现构造子件的接口
* Created by 拂晓 on 2019/7/26:20:17
*/
public class SxtAirShipBuilder implements AirShipBuilder{ //StringBuilder 以后学习的XML解析中,都用到了 建造者模式
@Override
public OrbitalModule builderOrbitalModule() {
System.out.println("构建轨道舱");
return new OrbitalModule();
}
@Override
public Engine builderEngine() {
System.out.println("构建发动机");
return new Engine();
}
@Override
public EscapeTower builderEscapeTower() {
System.out.println("构建逃生舱");
return new EscapeTower();
}
}
package com.builder;
/**
*
*
* Created by 拂晓 on 2019/7/26:20:16
*/
public interface Director {
AirShip createAirShip();//组装飞船对象
}
package com.builder;
/**
*
* 组装宇宙飞船的实现
*
* Created by 拂晓 on 2019/7/26:20:23
*/
public class SxtAirShipDirector implements Director {
private AirShipBuilder airShipBuilder;
public SxtAirShipDirector(AirShipBuilder airShipBuilder) {
this.airShipBuilder = airShipBuilder;
}
@Override
public AirShip createAirShip() {
Engine e = airShipBuilder.builderEngine();
OrbitalModule o = airShipBuilder.builderOrbitalModule();
EscapeTower es = airShipBuilder.builderEscapeTower();
//装配成飞船对象
AirShip ship = new AirShip();
ship.setEngine(e);
ship.setEscapeTower(es);
ship.setOrbitalModule(o);
return ship;
}
}
package com.builder;
/**
*
* 测试建造者模式
* Created by 拂晓 on 2019/7/26:20:29
*/
public class Client {
public static void main(String[] args) {
Director director = new SxtAirShipDirector(new SxtAirShipBuilder());
AirShip airShip = director.createAirShip();
System.out.println(airShip.getEngine().getName());
airShip.Launch();
}
}
-
开发中的应用场景:
- StringBuilder类中的append方法
- SQL中的PreparedSatement
- JDOM中,DomBuilder,SQXBuilder
原型模式(克隆模式)
作用:提高创建对象效率,类似于new,但是不同于new,new创建新的对象属性采用的是默认值,克隆出的对象的属性值完全和原型对象相同,并且克隆出的对象不会影响原型对象
原型模式实现
-
Cloneable接口和clone方法 (浅克隆)
package com.prototype; import java.util.Date; /** * Created by 拂晓 on 2019/7/26:21:33 */ public class Sheep implements Cloneable { private String name; private Date birthday; @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone();//直接调用Object的clone()方法! return obj; } public Sheep() { } public Sheep(String name, Date birthday) { this.name = name; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } package com.prototype; import java.util.Date; /** * * 测试原型模式(浅克隆) * Created by 拂晓 on 2019/7/26:21:38 */ public class Client { public static void main(String[] args) throws CloneNotSupportedException { Sheep s1 = new Sheep("少利",new Date(1123233L)); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthday()); Sheep s2 =(Sheep) s1.clone(); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthday()); } }
-
深克隆
package com.prototype; import java.util.Date; /** * Created by 拂晓 on 2019/7/26:21:33 */ public class Sheep implements Cloneable { private String name; private Date birthday; @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone();//直接调用Object的clone()方法! //添加如下代码实现深克隆 Sheep s =(Sheep)obj; s.birthday = (Date)this.birthday.clone();//把属性也进行clone() return obj; } public Sheep() { } public Sheep(String name, Date birthday) { this.name = name; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } package com.prototype; import java.util.Date; /** * * 原型模式测试(深克隆) * * Created by 拂晓 on 2019/7/26:21:55 */ public class client2 { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(1232323L); Sheep s1 = new Sheep("少利",date); Sheep s2 =(Sheep) s1.clone();//s2的birthday是一个新对象 System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthday()); date.setTime(23232423L); System.out.println(s1.getBirthday()); s2.setName("多利"); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthday()); } }
-
Prototype实现(实现起来困难的地方在于内存复制操作,所幸在Java中提供了clone方法)
序列化和反序列化实现深克隆
package com.prototype; import java.io.Serializable; import java.util.Date; /** * Created by 拂晓 on 2019/7/26:22:09 */ public class Sheep2 implements Cloneable,Serializable { private String name; private Date birthday; @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone();//直接调用Object的clone()方法! return obj; } public Sheep2() { } public Sheep2(String name, Date birthday) { this.name = name; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } package com.prototype; import java.io.*; import java.util.Date; /** * * 原型模式测试(使用序列化和反序列化实现深克隆) * * Created by 拂晓 on 2019/7/26:21:55 */ public class Client3 { public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { Date date = new Date(1232323L); Sheep2 s1 = new Sheep2("少利",date); System.out.println(s1); System.out.println(s1.getName()); System.out.println(s1.getBirthday()); //使用序列化和反序列化实现深克隆 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos =new ObjectOutputStream(bos); oos.writeObject(s1); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois =new ObjectInputStream(bis); Sheep2 s2 =(Sheep2) ois.readObject();//克隆好的对象 date.setTime(23232423L); System.out.println(s1.getBirthday()); s2.setName("多利"); System.out.println(s2); System.out.println(s2.getName()); System.out.println(s2.getBirthday()); } } //测试代码运行时间的方法 long start = System.currentTimeMillis(); Long end = System.currentTimemills(); System.out.println("程序运行的时间:"+(end-start));
-
开发中的应用场景
- 原型模式很少单独出现,一般和工厂方法模式一起出现,通过clone的方法创建出一个对象,然后由工厂方法提供给调用者
- Spring中的bean的创建实际就是两种:单例模式和原型模式(当然原型模式需要和工厂模式搭配起来)
- 通过new对象时很耗时间就可以通过原型模式
2.结构型模式:
关注对象和类的组织
作用: 从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题,
适配器模式
作用:将一个类的接口转换成另一个接口,使得原来那些接口不兼容的类可以在一起工作
模式中的角色:
- 目标接口(Target):客户所期待的接口,目标可以具体的或抽象的类,也可以时接口
- 需要适配的类(Adaptee):需要适配的类或者类
- 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口
适配器模式实现:
- 类适配器方式
package com.adapter;
/**
*
* 被适配的类
* 相当于PS/2键盘
* Created by 拂晓 on 2019/7/27:10:52
*/
public class Adaptee {
public void request(){
System.out.println("可以完成客户请求的需要的功能");
}
}
package com.adapter;
/**
* Created by 拂晓 on 2019/7/27:10:56
*/
public interface Target {
void handleReq();
}
package com.baizhi.adapter;
/**
*
* 适配器(类适配器方式)
* 相当于USB和PS/2的适配器
* Created by 拂晓 on 2019/7/27:10:57
*/
public class Adapter extends Adaptee implements Target{
@Override
public void handleReq() {
super.request();
}
}
package com.adapter;
/**
* 客户端类
* 相当于笔记本,只有USB接口
* Created by 拂晓 on 2019/7/27:10:54
*/
public class Client {
public void test1(Target t){
t.handleReq();
}
public static void main(String[] args) {
Client c = new Client();
//需要适配的对象
Adaptee a = new Adaptee();
Target t = new Adapter();
c.test1(t);
}
}
-
对象适配器方式
package com.adapter; /** * * 被适配的类 * 相当于PS/2键盘 * Created by 拂晓 on 2019/7/27:10:52 */ public class Adaptee { public void request(){ System.out.println("可以完成客户请求的需要的功能"); } } package com.adapter; /** * Created by 拂晓 on 2019/7/27:10:56 */ public interface Target { void handleReq(); } package com.adapter; /** * * 适配器(对象适配器方式,使用组合的方式跟被适配对象整合) * 相当于USB和PS/2的适配器 * Created by 拂晓 on 2019/7/27:10:57 */ public class Adapter2 implements Target{ private Adaptee adaptee; @Override public void handleReq() { adaptee.request(); } public Adapter2(Adaptee adaptee){ super(); this.adaptee = adaptee; } } package com.adapter; /** * 客户端类 * 相当于笔记本,只有USB接口 * Created by 拂晓 on 2019/7/27:10:54 */ public class Client { public void test1(Target t){ t.handleReq(); } public static void main(String[] args) { Client c = new Client(); //需要适配的对象 Adaptee a = new Adaptee(); Target t =new Adapter2(a); c.test1(t); } }
-
应用场景:
-
用来做旧系统改造和升级
-
java.io.InputStreamReader(InputStream)
-
java.io.OutputStreamWriter(OutputStream)
-
桥接模式
介绍:
桥接模式是设计Java虚拟机和实现JDBC等驱动程序的核心模式之一,应用较为广泛。在软件开发中如果一个类或一个系统有多个变化维度时,都可以尝试使用桥接模式对其进行设计。桥接模式为多维度变化的系统提供了一套完整的解决方案,并且降低了系统的复杂度。
作用:处理多层继承结构,处理多维度变化场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联
主要优点
桥接模式的主要优点如下:
(1)分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
(2)在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
(3)桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。
主要缺点
桥接模式的主要缺点如下:
(1)桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
适用场景
在以下情况下可以考虑使用桥接模式:
(1)如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
(2)“抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
(3)一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
(4)对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
装饰者模式
作用:动态的为一个对象增加一个新的功能,用于替代继承技术,无须通过继承增加子类就能增加新的功能
实现细节:
- Component抽象构件角色:真实对象和装饰对象有相同的接口,这样客户端对象就能够以与真实对象相同的方式同装饰对象交互
- ConcreteComponent具体构件角色(真实对象):io流中的FileInputStream,FileOutputStream
- Decorator装饰角色:持有一个抽象构件的引用,装饰对象接受所有客户端的请求,并把这些请求转发给真实对象,这样就能再真实对象调用前后增加新的功能
- ConcreteDecorator具体装饰角色:负责给构件对象增加新的责任
实现:
package com.decorator;
/**
* Created by 拂晓 on 2019/7/27:19:04
*/
//抽象组件
public interface ICar {
void move();
}
//真实对象 被装饰对象
class Car implements ICar{
@Override
public void move() {
System.out.println("陆地上跑");
}
}
//装饰器
class SuperCar implements ICar{
//作为装饰器需要持有一个真实对象的引用
protected ICar car;
public SuperCar(ICar car) {
this.car = car;
}
@Override
public void move() {
car.move();
}
}
class FlyCar extends SuperCar{
public FlyCar(ICar car) {
super(car);
}
public void fly(){
System.out.println("天上飞");
}
@Override
public void move() {
super.move();
fly();
}
}
class WaterCar extends SuperCar{
public WaterCar(ICar car) {
super(car);
}
public void swim(){
System.out.println("水上游");
}
@Override
public void move() {
super.move();
swim();
}
}
class AICar extends SuperCar{
public AICar(ICar car) {
super(car);
}
public void autoMove(){
System.out.println("自动导航");
}
@Override
public void move() {
super.move();
autoMove();
}
}
package com.decorator;
/**
*
* 测试装饰者模式
* Created by 拂晓 on 2019/7/27:19:12
*/
public class Client {
public static void main(String[] args) {
Car car =new Car();
car.move();
System.out.println("增加天上飞的功能");
FlyCar flyCar =new FlyCar(car);
flyCar.move();
System.out.println("增加水上跑的功能");
WaterCar waterCar = new WaterCar(car);
waterCar.move();
System.out.println("增加组合水上跑天上飞的功能");
WaterCar waterCar1 = new WaterCar(flyCar);
waterCar1.move();
}
}
-
应用场景:
- IO中输入流和输出流的设计
- Swing包中图形界面构件功能
- Servlet API中提供一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper类,增强了request对象的功能
- Struts2中,request,response,session对象的处理
-
总结:
- 优点:
- 装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类
- 扩展对象功能,比继承灵活,不会导致类个数的增加
- 可以对uige对象进行多次装饰,创造出不同的组合,得到功能更强大的对象
- 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类
- 缺点:
- 产生很多小对象,大量小对象占据内存,一定程度上影响性能
- 装饰模式易于出错,调式排查比较麻烦
- 装饰模式和桥接模式的区别
- 两个模式都是为了解决过多子类对象问题,但是他们的诱因不一样,桥接模式式对象自身现有机制沿着多个维度变化,是既有部分不稳定,装饰模式是为了增加新的功能
- 优点:
组合模式
作用:把部分和整体部分关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象
实现:
package com.composite;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 拂晓 on 2019/7/27:16:14
*/
//抽象构建
public interface AbstractFile {
void killVirus();//杀毒
}
class ImageFile implements AbstractFile{
private String name;
public ImageFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("=====图像文件====="+name+",进行查杀");
}
}
class TextFile implements AbstractFile{
private String name;
public TextFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("=====文本文件====="+name+",进行查杀");
}
}
class VideoFile implements AbstractFile{
private String name;
public VideoFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
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 AbstractFile getChild(int index){
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("====文件夹===="+name+",进行查杀");
for(AbstractFile file: list){
file.killVirus();
}
}
}
package com.composite;
/**
* Created by 拂晓 on 2019/7/27:16:26
*/
public class Client {
public static void main(String[] args) {
AbstractFile f2,f3,f4,f5;
Folder f1 = new Folder("我的收藏");
f2 = new ImageFile("图像文件.jpg");
f3 = new TextFile("书籍.txt");
f1.add(f2);
f1.add(f3);
Folder f11 = new Folder("电影");
f4 = new VideoFile("笑傲江湖.avi");
f5 =new VideoFile("神雕侠侣.avi");
f11.add(f4);
f11.add(f5);
f1.add(f11);
f1.killVirus();
}
}
-
应用场景:
- 操作系统的资源管理器
- GUI中的容器层次图
- XML文件解析
- OA系统中,组织结构的处理
- Junit单元测试框架
- 底层设计就是典型的组合模式,TestCase(叶子),TestUnite(容器),Test接口(抽象)
外观模式
迪米特法则(最少知识原则):一个软件实体应当尽可能少的与其他实体发生相互作用
作用:为子系统提供一个统一的入口,封装子系统的复杂性,便于客户端调用
实现:
package com.facade;
/**
* Created by 拂晓 on 2019/7/27:19:53
*/
public interface 工商局 {
void checkName(); //核名
}
class 海淀区工商局 implements 工商局{
@Override
public void checkName() {
System.out.println("检查名字是否有冲突");
}
}
package com.facade;
/**
* Created by 拂晓 on 2019/7/27:19:55
*/
public interface 税务局 {
void taxCertificate();
}
class 海淀税务局 implements 税务局{
@Override
public void taxCertificate() {
System.out.println("在海淀税务局办理税务登记证");
}
}
package com.baizhi.facade;
/**
* Created by 拂晓 on 2019/7/27:19:59
*/
public interface 质检局 {
void orgCodeCertificate(); //办理组织机构代码证
}
class 海淀质检局 implements 质检局{
@Override
public void orgCodeCertificate() {
System.out.println("在海淀区质检局办理组织机构代码证");
}
}
package com.facade;
/**
* Created by 拂晓 on 2019/7/27:19:57
*/
public interface 银行 {
void openAccount(); //开户
}
class 中国工商银行 implements 银行{
@Override
public void openAccount() {
System.out.println("在中国工商银行开户");
}
}
package com.facade;
/**
* Created by 拂晓 on 2019/7/27:20:04
*/
//办理注册公司流程的外观类
public class RegisterFacade {
public void register(){
工商局 a = new 海淀区工商局();
a.checkName();
质检局 b = new 海淀质检局();
b.orgCodeCertificate();
税务局 c = new 海淀税务局();
c.taxCertificate();
银行 d =new 中国工商银行();
d.openAccount();
}
}
package com.facade;
/**
* Created by 拂晓 on 2019/7/27:19:42
*/
//使用外观模式
public class Client {
public static void main(String[] args) {
RegisterFacade facade = new RegisterFacade();
facade.register();
}
}
-
应用场景;
- 频率很高,哪里都会遇到,各种技术和框架中,都有外观模式的使用
- JDBC封装后的,commons提供的DBUtils类,
- Hibernate提供的工具类,Spring JDBC工具类等
享元模式(共享数据)
作用:如果系统中存在多个完全相同或相似的对象,我们可以通过享元模式,节省内存;
模式中的角色:
- FlyweightFactory享元工厂类
- 创建并管理享元对象,享元池一般设计成键值对
- FlyWeight抽象享元类
- 通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态.
- ConcreteFlyWeight具体享元类
- 为内部状态提供成员变量进行存储
- UnsharedConcreteFlyWeight非共享享元类
- 不能被共享的子类可以设计为非共享享元类
实现:
package com.flyweight;
/**
* Created by 拂晓 on 2019/7/27:20:44
*/
//享元类
public interface ChessFlyWeight {
void setColor(String c);
String getColor();
void display(Coordinate c);
}
//具体享元类对象
class ConcreateChess implements ChessFlyWeight{
//内部状态
private String color;
public ConcreateChess(String color) {
this.color = color;
}
@Override
public void setColor(String c) {
this.color=c;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate c) {
System.out.println("棋子颜色:"+color);
System.out.println("棋子位置:"+c.getX()+"===="+c.getY());
}
}
package com.flyweight;
import java.util.HashMap;
import java.util.Map;
/**
* Created by 拂晓 on 2019/7/27:21:01
*/
//享元工厂
public class ChessFlyWeightFactroy {
//享元池 池就是容器
private static Map<String,ChessFlyWeight> map = new HashMap<>();
public static ChessFlyWeight getChess(String color){
if(map.get(color)!=null){
return map.get(color);
}
else {
ChessFlyWeight cfw = new ConcreateChess(color);
map.put(color,cfw);
return cfw;
}
}
}
package com.flyweight;
/**
* Created by 拂晓 on 2019/7/27:20:55
*/
//外部状态
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;
}
}
package com.flyweight;
/**
*
* 测试享元模式
* Created by 拂晓 on 2019/7/27:21:07
*/
public class Client {
public static void main(String[] args) {
ChessFlyWeight chess1 = ChessFlyWeightFactroy.getChess("黑色");
ChessFlyWeight chess2 = ChessFlyWeightFactroy.getChess("黑色");
System.out.println(chess1);
System.out.println(chess2);
System.out.println("增加外部状态的处理=======");
chess1.display(new Coordinate(10,10));
chess2.display(new Coordinate(20,20));
}
}
-
享元模式开发中应用的场景:
- 享元模式由于其共享的特性,可以在任何"池"中操作,比如:线程池,数据库连接池
- String类的串池设计也是享元模式
-
优点:
- 极大减少内存中对象那个的数量
- 相同或相似对象内存中只存一份,极大的节约资源,提高系统性能
- 外部状态相对独立,不影响内部状态
-
缺点:
-
模式较为复杂,使程序逻辑复杂化
-
为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长,用时间换取了空间
-
代理模式(Proxy)
作用:通过代理,控制对对象的访问,AOP(Aspect Oriented Programming面向切面编程) 的核心实现机制
应用场景:
- 安全代理:屏蔽对真实角色的直接访问
- 远程代理:通过代理类处理远程方法调用(RmI)
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象
分类:
- 静态代理(静态定义代理类)
- 动态代理(动态生成代理类)
- JDK自带的动态代理
- javaassist字节码操作库实现
- CGLIB
- ASM(底层使用指令,可维护性差)
实现:
-
静态代理类
package com.staticProxy; /** * Created by 拂晓 on 2019/7/27:13:47 */ public interface Star { void confer();//面谈 void signContract();//签合同 void bookTicket();//订票 void sing();//唱歌 void collectmoney();//收钱 } package com.staticProxy; /** * Created by 拂晓 on 2019/7/27:13:48 */ public class RealStar implements Star { @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.singContract()"); } @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void sing() { System.out.println("RealStar.sing()"); } @Override public void collectmoney() { System.out.println("RealStar.collectmoney()"); } } package com.staticProxy; /** * Created by 拂晓 on 2019/7/27:13:51 */ public class ProxyStar implements Star { //代理类需要代理的对象 private Star star; @Override public void confer() { System.out.println("ProxyStar.confer()"); } @Override public void signContract() { System.out.println("ProxyStar.singContract()"); } @Override public void bookTicket() { System.out.println("ProxyStar.bookTicket()"); } @Override public void sing() { star.sing(); } @Override public void collectmoney() { System.out.println("ProxyStar.collectmoney()"); } public ProxyStar(Star star) { this.star = star; } } package com.staticProxy; /** * Created by 拂晓 on 2019/7/27:13:54 */ public class Client { public static void main(String[] args) { Star real = new RealStar(); Star proxy =new ProxyStar(real); proxy.signContract(); proxy.bookTicket(); proxy.collectmoney(); proxy.confer(); proxy.sing(); } }
-
动态代理类(动态生成代理类)
-
JDK自带的动态代理
package com.dynamicProxy; /** * Created by 拂晓 on 2019/7/27:13:47 */ public interface Star { void confer();//面谈 void signContract();//签合同 void bookTicket();//订票 void sing();//唱歌 void collectmoney();//收钱 } package com.dynamicProxy; /** * Created by 拂晓 on 2019/7/27:13:48 */ public class RealStar implements com.baizhi.dynamicProxy.Star { @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.singContract()"); } @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void sing() { System.out.println("RealStar.sing()"); } @Override public void collectmoney() { System.out.println("RealStar.collectmoney()"); } } package com.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /**动态代理类 * Created by 拂晓 on 2019/7/27:15:12 */ public class StarHandler implements InvocationHandler { Star realStar ; public StarHandler(Star realStar) { this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object =null; System.out.println("ProxyStar.confer()"); System.out.println("ProxyStar.singContract()"); if(method.getName().equals("sing")) { object = method.invoke(realStar, args); } System.out.println("ProxyStar.bookTicket()"); System.out.println("ProxyStar.collectmoney()"); return object; } } package com.dynamicProxy; import java.lang.reflect.Proxy; /** * 测试动态代理的JDK实现 * Created by 拂晓 on 2019/7/27:15:14 */ public class Client { public static void main(String[] args) { Star realStar = new RealStar(); StarHandler handler = new StarHandler(realStar); Star proxy =(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.sing(); } }
-
开发框架种应用场景:
- struts2种拦截器的实现
- 数据库连接池关闭处理
- Hibernate种延时加载的实现
- mybatis中实现拦截器插件
- AspectJ的实现
- Spring中AOP的实现
- 日志拦截
- 声明式事务处理
- web service
- RMI远程方法调用
- …
3.行为型模式
关注系统中对象质检的相互交互研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责,共有11中模式
模板方法模式(重要)
作用:帮助定义了一个操作种的算法骨架,将某些步骤延迟到子类实现,使新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤,简单来说,就是:处理步骤父类种定义好,具体实现延迟到子类中定义
场景:
- 客户到银行办理业务:
- 取号排队
- 办理具体现金/转账/企业/个人/理财业务
- 给银行工作人员评分
实现:
package com.templateMethod;
/**
* Created by 拂晓 on 2019/7/28:21:51
*/
public abstract class BankTemplateMethod {
//具体方法
public void takeNumber(){
System.out.println("取号排队");
}
public abstract void transact();
public void evaluate(){
System.out.println("反馈评分");
}
//模板方法不能被子类重写
public final void process(){
this.takeNumber();
this.transact();
this.evaluate();
}
}
//定义子类继承BankTemplateMethod实现里面的抽象方法
class DrawMoney extends BankTemplateMethod{
@Override
public void transact() {
System.out.println("我要取款");
}
}
package com.templateMethod;
/**
* 测试模板方法模式
* Created by 拂晓 on 2019/7/28:21:54
*/
public class Client {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
//也可以采用匿名内部类
BankTemplateMethod btm2 = new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要存钱");
}
};
btm2.process();
BankTemplateMethod btm3 = new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要理财");
}
};
btm3.process();
}
}
-
什么时候使用模板方法模式?
实现一个算法时,整体步骤很固定,但是,某些部分易变,易变部分可以抽象出来,供子类实现
-
应用场景:
- 数据库访问的封装
- Junit单元测试
- servlet中关于doGet/doPost方法调用
- Hibernate中模板程序
- spring中JDBCTemplate ,HibernateTemplate等
命令模式
使用概率低,作为了解
作用:将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作;也称之位:动作Action模式,事务transaction模式
结构:
- Command抽象命令类
- ConcreteCommand具体命令类
- Invoker调用者/请求者
- 请求的发送者,它通过命令对象来执行请求,一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联,程序运行时,将调用命令对象的execute(),间接调用接收者的相关操作
- Receiver接收者
- 接收者执行与请求相关的操作,具体实现对请求的业务处理
- 未抽象前,实际执行操作内容的对象
- Client客户类
- 在客户类中需要创建调用者对象,具体命令类对象,在创建具体命令对象时指定对应的接收者,发送者和接收者之间没有直接关系,都通过命令对象间接调用
实现:
package com.command;
/**
* 真正的命令执行者
* Created by 拂晓 on 2019/7/28:20:32
*/
public class Receiver {
public void action(){
System.out.println("Receiver.action");
}
}
package com.baizhi.command;
/**
*
* Created by 拂晓 on 2019/7/28:20:33
*/
public interface Command {
/**
* 这个方法是一个返回结果为空的方法
* 实际项目中,可以根据此需求设计多个不同的方法
*/
void execute();
}
class ConcreteCommand implements Command{
private Receiver receiver;//命令真正的执行者
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
//命令真正执行前或执行后,执行相关的处理
receiver.action();
}
}
package com.command;
/**
*
*调用者||发起者
* Created by 拂晓 on 2019/7/28:20:36
*/
public class Invoke {
//也可以通过List<Command>容纳很多命令对象,进行批处理,数据库底层的事务管理就是类似的结构
private Command command;
public Invoke(Command command) {
this.command = command;
}
//业务方法,用于调用命令的方法
public void call(){
//可以在调用前或者调用后做一些处理
command.execute();
}
}
package com.command;
/**
* 测试命令模式
*
* Created by 拂晓 on 2019/7/28:20:39
*/
public class Client {
public static void main(String[] args) {
Command c = new ConcreteCommand(new Receiver());
Invoke i = new Invoke(c);
i.call();
}
}
-
应用场景:
- Struts2中,action的整个调用过程中就有命令模式
- 数据库事务机制的底层实现
- 命令的撤销和恢复
迭代器模式
作用:
场景:
- 提供一种可以遍历聚合对象的方式
- 聚合对象:存储数据
- 迭代器:遍历数据
实现:
package com.iterator;
/**
* Created by 拂晓 on 2019/7/28:9:12
*/
//自定义迭代器接口
public interface MyIterator {
void first();//将游标指向第一个元素
void next();//将游标指向下一个元素
boolean hasNext();//判断是否存在下一个元素
boolean isFirst();
boolean isLast();
Object getCurrentObject();//获取当前游标指向的对象
}
package com.iterator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 拂晓 on 2019/7/28:9:15
*/
//自定义的聚合类
public class ConcreteMyAggregate {
//定义容器
private List<Object> list = new ArrayList<>();
public ConcreteMyAggregate() {
}
public void addObject(Object obj){
this.list.add(obj);
}
public void removeObject(Object obj){
this.list.remove(obj);
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
public MyIterator crecteIterrator(){
return new ConcreteIterator();
}
//使用内部类定义迭代器 可以直接使用外部类的属性
private class ConcreteIterator implements MyIterator{
private int cursor; //定义游标用于记录遍历时的位置
@Override
public void first() {
cursor= 0 ;
}
@Override
public void next() {
if(cursor<list.size()) {
cursor++;
}
}
@Override
public boolean hasNext() {
if(cursor<list.size()){
return true;
}
return false;
}
@Override
public boolean isFirst() {
return cursor==0?true:false;
}
@Override
public boolean isLast() {
return cursor==(list.size()-1)?true:false;
}
@Override
public Object getCurrentObject() {
return list.get(cursor);
}
}
}
package com.iterator;
/**
*
* 测试迭代器模式
* Created by 拂晓 on 2019/7/28:11:43
*/
public class Client {
public static void main(String[] args) {
//创建聚合对象
ConcreteMyAggregate cma = new ConcreteMyAggregate();
cma.addObject("aa");
cma.addObject("bb");
cma.addObject("cc");
MyIterator iter = cma.crecteIterrator();
while (iter.hasNext()){
System.out.println(iter.getCurrentObject());
iter.next();
}
}
}
-
应用场景:
- JDK内置的迭代器List/Set
观察者模式(Observer)
作用:一对多的通知,当一个目标对象的状态变化时,他需要及时告知一系列观察者对象,令他们做出相应
通知观察者的方式:
- 推
- 每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动接受
- 拉
- 观察者只要知道有情况即可,至于什么时候获取内容,获取什么内容,都可以自主决定
实现:
package com.observer;
/**
* Created by 拂晓 on 2019/8/4:20:51
*/
public interface Observer {
void update(Subject subject);
}
package com.observer;
/**
* Created by 拂晓 on 2019/8/4:21:01
*/
public class ObserverA implements Observer {
//myState需要跟目标对象的state值保持一致
private int myState;
@Override
public void update(Subject subject) {
myState =((ConcreteSubject)subject).getState();
}
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
}
package com.observer;
import java.util.ArrayList;
import java.util.List;
/**
* Created by 拂晓 on 2019/8/4:20:53
*/
public class Subject {
protected List<Observer> list = new ArrayList<>();
//增加观察者
public void register(Observer obs){
list.add(obs);
}
//删除观察者
public void removeObserver(Observer obs){
list.remove(obs);
}
//通知所有观察者更新状态
public void notifyObservers(){
for (Observer obs : list) {
obs.update(this);
}
}
}
package com.observer;
/**
* Created by 拂晓 on 2019/8/4:20:58
*/
public class ConcreteSubject extends Subject {
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
//目标对象值发生了变化,请通知所有观察者
this.notifyObservers();
}
}
package com.observer;
/**测试观察者模式
* Created by 拂晓 on 2019/8/4:21:05
*/
public class Client {
public static void main(String[] args) {
//创建目标对象
ConcreteSubject subject = new ConcreteSubject();
//创建多个观察者
ObserverA obs1 = new ObserverA();
ObserverA obs2 = new ObserverA();
ObserverA obs3 = new ObserverA();
//让三个观察者加入Subject对象的观察者队伍中
subject.register(obs1);
subject.register(obs2);
subject.register(obs3);
//改变Subject的状态
subject.setState(3000);
//看观察者的状态有没有变化
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
}
}
-
通过java.util.Observer来实现观察者模式
package com.observer2; import java.util.Observable; /** * 目标对象 * Created by 拂晓 on 2019/8/4:21:17 */ public class ConcreteSubject extends Observable { private int state; public void set(int s ){ state = s ;//目标对象的状态发生了改变 setChanged(); //表示目标对象已经做了更改 notifyObservers(state);//通知多有的观察者 } public int getState() { return state; } public void setState(int state) { this.state = state; } } package com.observer2; import java.util.Observable; import java.util.Observer; /** * Created by 拂晓 on 2019/8/4:21:21 */ public class ObserverA implements Observer { private int myState; @Override public void update(Observable o, Object arg) { myState = ((ConcreteSubject)o).getState(); } public int getMyState() { return myState; } public void setMyState(int myState) { this.myState = myState; } } package com.observer2; /** * * 测试java.util.Observer实现观察者模式 * Created by 拂晓 on 2019/8/4:21:23 */ public class Client { public static void main(String[] args) { //创建目标对象Obserable ConcreteSubject subject = new ConcreteSubject(); //创建观察者 ObserverA obs1= new ObserverA(); ObserverA obs2= new ObserverA(); ObserverA obs3= new ObserverA(); //将上面三个观察者对象添加导目标对象subject的观察者容器中 subject.addObserver(obs1); subject.addObserver(obs2); subject.addObserver(obs3); //改变subject对象的状态 subject.set(3000); //查看观察者的状态 System.out.println(obs1.getMyState()); System.out.println(obs2.getMyState()); System.out.println(obs3.getMyState()); } }
应用场景:
- 聊天室程序的,服务器转发给所有客户端
- 网络游戏创景中,服务器将客户端的状态进行分发
- 邮件订阅
- Servlet中,监听器的实现
- Android,广播机制
- JDK的AWT中事件处理模型,基于观察者模式的委派事件模型
- 事件源-------目标对象
- 事件监听器----观察者
- 京东商城,群发某件商品打折信息
中介者模式
作用:把对象之间存在的大量多对多关系,使用中介者模式化解成一对多结构,解耦多个同级对象的交互关系,每个对象都持有中介者对象,只跟中介者对象打交道,通过中介者对象管理这些交互关系
实现:
package com.mediator;
/**
* Created by 拂晓 on 2019/7/28:19:37
*/
//同事类的接口
public interface Department {
void selfAction();//做本部门的事情
void outAction();//向总经理发出申请
}
package com.mediator;
/**
* Created by 拂晓 on 2019/7/28:19:38
*/
//财务部类
public class Finacial implements Department {
private Mediator m;//持有中介者(总经理)
public Finacial(Mediator m) {
this.m = m;
m.register("finacial",this);
}
@Override
public void selfAction() {
System.out.println("数钱");
}
@Override
public void outAction() {
System.out.println("财务部,汇报工作");
}
}
package com.mediator;
/**
* Created by 拂晓 on 2019/7/28:19:38
*/
//市场部
public class Market implements Department {
private Mediator m;//持有中介者(总经理)
public Market(Mediator m) {
this.m = m;
m.register("Market",this);
}
@Override
public void selfAction() {
System.out.println("接项目");
}
@Override
public void outAction() {
System.out.println("市场部,汇报工作");
m.command("finacial");
}
}
package com.mediator;
/**
* Created by 拂晓 on 2019/7/28:19:38
*/
//研发部
public class Development implements Department {
private Mediator m;//持有中介者(总经理)
public Development(Mediator m) {
this.m = m;
m.register("development",this);
}
@Override
public void selfAction() {
System.out.println("专心科研,开发项目");
}
@Override
public void outAction() {
System.out.println("汇报工作,需要资金支持");
}
}
package com.mediator;
/**
* Created by 拂晓 on 2019/7/28:19:35
*/
public interface Mediator {
void register(String dname, Department d);
void command(String dname);
}
package com.mediator;
import java.util.HashMap;
import java.util.Map;
/**
* Created by 拂晓 on 2019/7/28:19:48
*/
//中介者
public class President implements Mediator{
private Map<String,Department> map = new HashMap<>();
@Override
public void register(String dname, Department d) {
map.put(dname, d);
}
@Override
public void command(String dname) {
map.get(dname).selfAction();
}
}
package com.mediator;
/**
*
* 测试中介者模式
* Created by 拂晓 on 2019/7/28:19:51
*/
public class Client {
public static void main(String[] args) {
Mediator m = new President();
Market market = new Market(m);
Development devp = new Development(m);
Finacial finacial = new Finacial(m);
market.selfAction();
market.outAction();
}
}
-
应用场景:
- MVC模式(其中的C,控制器就是一个中介者对象,M和V都和他打交道)
- 窗口游戏程序,窗口软件开发中窗口对象也是一个中介者对象
- 图形界面开发GUI中,多个组件之间的交互,可以通过引入一个中介者,对象来解决,可以是整体的窗口对象或者DOM对象
备忘录模式(memento)
作用: 就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态
场景:
-
录入大批人员资料,正在录入当前人资料时,发现上一个录错了,此时需要恢复上一个人的资料,再进行修改.
-
Word文档编辑时,忽然电脑死机或者断电,再打开时,可以看到word提示你恢复到以前的文档
-
管理系统中,公文撤回功能,公文发送出去后,想撤回;
结构:
- 源发器类Originator:可以保存对象内部的状态
- 备忘录类Memento:负责存储拷贝
- 负责人类Care Take :用来存储备忘录
实现:
package com.memento;
/**
* 源发器类
* Created by 拂晓 on 2019/8/4:21:44
*/
public class Emp {
private String name;
private int age;
private double salary;
//进行备忘操作,并返回备忘录对象
public EmpMemento memento(){
return new EmpMemento(this);
}
//进行数据恢复,恢复成指定备忘录对象的值
public void recovery(EmpMemento mmt){
this.name = mmt.getName();
this.age = mmt.getAge();
this.salary = mmt.getSalary();
}
public Emp(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Emp() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.memento;
import java.util.ArrayList;
import java.util.List;
/**
*
* 负责人,类
* 负责管理备忘录对象
* Created by 拂晓 on 2019/8/4:21:51
*/
public class CareTaker {
//保存一次
private EmpMemento memento;
//保存多次
private List<EmpMemento> list = new ArrayList<>();
public EmpMemento getMemento() {
return memento;
}
public void setMemento(EmpMemento memento) {
this.memento = memento;
}
}
package com.baizhi.memento;
/**
*
* 备忘录类
* Created by 拂晓 on 2019/8/4:21:45
*/
public class EmpMemento {
private String name;
private int age;
private double salary;
public EmpMemento(Emp e) {
this.name=e.getName();
this.age =e.getAge();
this.salary =e.getSalary();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.memento;
/**
* 测试备忘录模式
* Created by 拂晓 on 2019/8/4:21:52
*/
public class Client {
public static void main(String[] args) {
CareTaker taker = new CareTaker();
Emp emp = new Emp("zhangSan",18,900);
System.out.println("第一次创建对象:"+emp.getName()+"-----"+emp.getAge()
+"-----"+emp.getSalary());
//备份一次
taker.setMemento(emp.memento());
emp.setName("liSi");
emp.setAge(30);
emp.setSalary(10000);
System.out.println("第二次创建对象:"+emp.getName()+"-----"+emp.getAge()
+"-----"+emp.getSalary());
//恢复到备忘录对象保存的状态
emp.recovery(taker.getMemento());
System.out.println("第三次创建对象:"+emp.getName()+"-----"+emp.getAge()
+"-----"+emp.getSalary());
}
}
-
备忘点较多时
-
将备忘录压栈
public class Care Taker{ private Memento memento; pivate Stack<Memento> stack = new Stack<Memento>(); }
-
将多个备忘录对象,序列化和持久化
-
应用场景:
- 棋类游戏中的,悔棋
- 普通软件中的,撤销操作
- 数据库软件中的,事务管理中的,回滚操作
- Photoshop软件中的历史记录
解释器模式
介绍:
-
是一种不常用的设计模式
-
当需要开发一种新的语言时,可以考虑使用解释器模式
-
尽量不要使用解释器模式,后期维护会有很大麻烦,在项目中可以使用Jruby,Groovy,java的js引擎来替代解释器的作用,弥补java语言的不足
作用:
- 用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计
实现: 因为实现过于复杂,而且并不常用,作为了解就可以
状态模式
作用:用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
结构:
- Context环境类
- 环境类中维护一个State对象,他是定义了当前的状态
- State抽象状态类
- ConcreteState具体类
- 每个类封装了一个状态对应的行为
场景:
- 酒店系统中,房间的状态变化:
- 已预定
- 已入住
- 空闲
实现:
package com.state;
/**
* Created by 拂晓 on 2019/7/28:22:20
*/
public interface State {
void handle();
}
package com.state;
/**
* 空闲状态
* Created by 拂晓 on 2019/7/28:22:20
*/
public class FreeState implements State {
@Override
public void handle() {
System.out.println("房间状态:空闲");
}
}
package com.baizhi.state;
/**
* 已预订状态
* Created by 拂晓 on 2019/7/28:22:20
*/
public class BookedState implements State {
@Override
public void handle() {
System.out.println("房间状态:已预定");
}
}
package com.baizhi.state;
/**
* 已入住状态
* Created by 拂晓 on 2019/7/28:22:20
*/
public class CheckedState implements State {
@Override
public void handle() {
System.out.println("房间状态:已入住");
}
}
package com.state;
/**
* 维持不同状态的切换
* 房间对象
* Created by 拂晓 on 2019/7/28:22:22
*/
public class Context {
//如果是银行系统 ,这个 Context类就是账号,根据金额不同,切换不同状态
private State state;
public void setState(State s){
System.out.println("修改状态");
state=s;
state.handle();
}
}
package com.state;
/**
* 测试状态模式
* Created by 拂晓 on 2019/7/28:22:25
*/
public class Client {
public static void main(String[] args) {
//创建房间对象
Context ctx = new Context();
//修改房间状态
ctx.setState(new FreeState());
ctx.setState(new BookedState());
ctx.setState(new CheckedState());
}
}
-
应用场景:
- 银行系统中账号状态的管理
- OA系统中公文状态的管理
- 酒店系统中,房间状态的管理
- 线程对象各状态之间的切换
策略模式
作用:解决某个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一个问题,同事可以方便的更换算法或者增加新的算法
场景:
- 某个市场人员接到单后的报价策略(CRM系统中常见问题),报价策略复杂,可以简单作如下分类:
- 普通客户小批量报价
- 普通客户大批量报价
- 老客户小批量报价
- 老客户大批量报价
- 具体选用哪个报价策略,这需要根据实际情况来确定,这时候,我们采用策略模式即可
实现:
-
可以使用采用条件语句处理
public double getPrice(String type,double price){ if(type.equals("普通客户小批量")){ System.out.println("不打折,原价"); return price; }else if(type.equals("普通客户大批量")){ System.out.println("打九折"); return price*0.9; }else if(type.equals("老客户小批量")){ System.out.println("打八五折"); return price*0.85; }else if(type.equals("老客户大批量")){ System.out.println("打八折"); return price*0.8; } return price ; }
但是,假如类型特别多,算法比较复杂时,整个条件控制代码会变得很长,难于维护,也违反开闭原则
-
使用策略模式
package com.strategy;
/**
* Created by 拂晓 on 2019/7/28:21:20
*/
public interface Strategy {
double getPrice(double standardPrice);
}
package com.strategy;
/**
* 普通客户小批量
* Created by 拂晓 on 2019/7/28:21:22
*/
public class NewCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("不打折,原价");
return standardPrice;
}
}
package com.strategy;
/**
* 普通客户大批量
* Created by 拂晓 on 2019/7/28:21:22
*/
public class NewCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打九折");
return standardPrice*0.9;
}
}
package com.strategy;
/**
* 老客户小批量
* Created by 拂晓 on 2019/7/28:21:22
*/
public class OldCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("八五折");
return standardPrice*0.85;
}
}
package com.strategy;
/**
* 老客户大批量
* Created by 拂晓 on 2019/7/28:21:22
*/
public class OldCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打八折");
return standardPrice*0.8;
}
}
package com.strategy;
/**
* 负责和具体的策略类交互
* 这样的话,具体的算法和直接客户端的调用分离了,使得算法可以独立于客户端的变化
* 如果使用Spring的依赖注入功能,还可以通过配置文件,动态注入不同的策略对象
* Created by 拂晓 on 2019/7/28:21:25
*/
public class Context {
private Strategy strategy;//当前采用的算法
//可以通过构造器来注入
public Context(Strategy strategy) {
this.strategy = strategy;
}
//也可以通过set方法来注入
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void pringPrice(double s){
System.out.println("您该报价: "+strategy.getPrice(s));
}
}
package com.strategy;
/**
* 测试策略模式
* Created by 拂晓 on 2019/7/28:21:31
*/
public class Client {
public static void main(String[] args) {
Strategy s1 = new OldCustomerManyStrategy();
Context ctx = new Context(s1);
ctx.pringPrice(998);
}
}
-
应用场景:
- JavaSE中GUI编程中,布局管理
- Spring框架中,Resource接口,资源访问策略
- javax.servlet.http.HttpServlet#service
责任链模式
作用:将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象
案例场景:
- 公司里面,请假条的审批流程
- 如果请假天数小于3天,主任审批
- 如果请假天数大于等于3天,小于10天,经理审批
- 如果大于等于10天,小于30天,总经理审批
- 如果大于等于30天,提示拒绝
实现:
package com.chainOfResp;
/**
* Created by 拂晓 on 2019/7/27:21:50
*/
//封装请假的基本信息
public class LeaveRequest {
private String empName;
private int leaveDays;
private String reason;
public LeaveRequest(String empName, int leaveDays, String reason) {
this.empName = empName;
this.leaveDays = leaveDays;
this.reason = reason;
}
public LeaveRequest() {
}
public String getEmpName() {
return empName;
}
public int getLeaveDays() {
return leaveDays;
}
public void setLeaveDays(int leaveDays) {
this.leaveDays = leaveDays;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public void setEmpName(String empName) {
this.empName = empName;
}
}
package com.chainOfResp;
/**
* Created by 拂晓 on 2019/7/27:21:52
*/
//抽象类
public abstract class Leader {
protected String name;
protected Leader nextLeader;//责任链上的后继对象
public Leader(String name) {
this.name = name;
}
//设定责任链上的后继对象
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
//处理请求的核心的业务方法
public abstract void handleRequest(LeaveRequest request);
}
package com.chainOfResp;
/**
* Created by 拂晓 on 2019/7/27:21:56
*/
//主任
public class Director extends Leader {
public Director(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDays()<3){
System.out.println("员工:"+request.getEmpName()+"请假,天数:"+request.getLeaveDays()+",理由:"+request.getReason());
System.out.println("主任:"+this.name+",审批通过!");
}else {
if (this.nextLeader!=null){
this.nextLeader.handleRequest(request);
}
}
}
}
package com.chainOfResp;
/**
* Created by 拂晓 on 2019/7/27:21:56
*/
//经理
public class Manager extends Leader {
public Manager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDays()<10){
System.out.println("员工:"+request.getEmpName()+"请假,天数:"+request.getLeaveDays()+",理由:"+request.getReason());
System.out.println("经理:"+this.name+",审批通过!");
}else {
if (this.nextLeader!=null){
this.nextLeader.handleRequest(request);
}
}
}
}
package com.chainOfResp;
/**
* Created by 拂晓 on 2019/7/27:21:56
*/
//总经理
public class GeneralManager extends Leader {
public GeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDays()<30){
System.out.println("员工:"+request.getEmpName()+"请假,天数:"+request.getLeaveDays()+",理由:"+request.getReason());
System.out.println("总经理:"+this.name+",审批通过!");
}else {
System.out.println("莫非"+request.getEmpName()+"想辞职,居然请假"+request.getLeaveDays()+"天!");
}
}
}
package com.chainOfResp;
/**
*
* 测试责任链模式
* Created by 拂晓 on 2019/7/27:22:05
*/
public class Client {
public static void main(String[] args) {
Leader a = new Director("张主任");
Leader b = new Manager("李经理");
Leader c = new GeneralManager("王总");
//责任链对象的关系
a.setNextLeader(b);
b.setNextLeader(c);
//开始请假操作
LeaveRequest req1 = new LeaveRequest("TOM",5,"回家探亲");
a.handleRequest(req1);
}
}
-
应用场景:
- Java中,异常机制就是一种责任链模式,一个try可以对应多个cath,当第一个catch不匹配类型,则自动跳到第二个catch
- JavaScript语言中,事件的冒泡和捕获机制,Java语言中,事件的处理采用观察者模式
- Servlet开发中,过滤器的链式处理
- Struts2中,拦截器的调用也是典型的责任链模式
访问者模式
使用频率不高,大多数情况下,不需要使用,作为了解
作用:封装一些作用于某种数据结构中的各元素的擦欧总,它可以不改变这个数据结构的前提下定义作用于这些元素的新操作
使用场景:
-
对象结构比较稳定,单经常需要在此对象结构定义新的操作
-
需要对一个对象那个结构中的进行很多不同且不想管的操作,而需要避免这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类
优点:
1、使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
2、添加新的操作或者说访问者会非常容易。
3、将对各个元素的一组操作集中在一个访问者类当中。
4、使得类层次结构不改变的情况下,可以针对各个层次做出不同的操作,而不影响类层次结构的完整性。
5、可以跨越类层次结构,访问不同层次的元素类,做出相应的操作。
缺点:
1、增加新的元素会非常困难。
2、实现起来比较复杂,会增加系统的复杂性。
3、破坏封装,如果将访问行为放在各个元素中,则可以不暴露元素的内部结构和状态,但使用访问者模式的时候,为了让访问者能获取到所关心的信息,元素类不得不暴露出一些内部的状态和结构,就像收入和支出类必须提供访问金额和单子的项目的方法一样。