23种设计模式模式笔记+易懂案例
Java设计模式
前言
这其实算我个人学习的一个笔记,我这里的标题只有22种,俗称的23种是因为工厂模式一般分为两种,工厂模式与抽象工厂。
一、设计模式是什么?
1.设计模式的定义
设计模式的一般定义如下:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过 分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性
2.设计模式的分类
类型 | 模式名称 |
---|---|
创建型模式 | 单例模式 |
创建型模式 | 简单工厂模式 |
创建型模式 | 工厂方法模式 |
创建型模式 | 抽象工厂模式 |
创建型模式 | 原型模式 |
创建型模式 | 建造者模式 |
结构型 | 适配器模式 |
结构型 | 桥接模式 |
结构型 | 组合模式 |
结构型 | 装饰模式 |
结构型 | 外观模式 |
结构型 | 享元模式 |
结构型 | 代理模式 |
行为型 | 责任链模式 |
行为型 | 命令模式 |
行为型 | 解释器模式 |
行为型 | 迭代器模式 |
行为型 | 中介者模式 |
行为型 | 备忘录模式 |
行为型 | 观察者模式 |
行为型 | 状态模式 |
行为型 | 策略模式 |
行为型 | 模板方法模式 |
行为型 | 访问者模式 |
二、设计模式的实现
1.工厂模式
(1)工厂三兄弟之简单工厂模式
package com.example.demo.pattern.creational;/*** 功能描述: 简单工厂模式** @author luxiaomeng* @date 2020/8/18 9:28* 修改日志: 暂无*/
public class SimpleFactoryPattern {public static void main(String[] args) {BaseProduct a = Factory.getProduct("A");System.out.println(a.productName());BaseProduct b = Factory.getProduct("B");System.out.println(b.productName());}
}/*** 我是水*/
abstract class BaseProduct {public abstract String productName();
}/*** 我是橙汁*/
class ProductA extends BaseProduct {@Overridepublic String productName() {return "I am A";}
}/*** 我是可乐*/
class ProductB extends BaseProduct {@Overridepublic String productName() {return "I am B";}
}/*** 我是工厂*/
class Factory {public static BaseProduct getProduct(String name){if ("A".equals(name)) {return new ProductA();}if ("B".equals(name)) {return new ProductB();}return new BaseProduct() {@Overridepublic String productName() {return "I am Base";}};}
}
由代码看出想要任何产品都得修改SimpleFactoryPattern类中main方法的代码,这里可以做一些优化。
创建config.xml
<?xml version="1.0" encoding="utf-8" ?>
<config><productType>A</productType>
</config>
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.*;
import java.io.File;/*** 功能描述: 简单工厂模式-优化** @author luxiaomeng* @date 2020/8/18 9:28* 修改日志: 暂无*/
public class SimpleFactoryPattern {public static void main(String[] args) throws Exception {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dbf.newDocumentBuilder();Document doc = builder.parse(new File("E:\\WorkSpace\\IDEA\\study\\src\\main\\java\\com\\example\\demo\\pattern\\creational\\plus\\config.xml"));NodeList nodeList = doc.getElementsByTagName("productType");Node classNode = nodeList.item(0).getFirstChild();String name = classNode.getNodeValue().trim();BaseProduct factory = Factory.getProduct(name);System.out.println( factory.productName());}
}/*** 我是水*/
abstract class BaseProduct {public abstract String productName();
}/*** 我是雪碧*/
class ProductA extends BaseProduct {@Overridepublic String productName() {return "I am A";}
}/*** 我是可乐*/
class ProductB extends BaseProduct {@Overridepublic String productName() {return "I am B";}
}/*** 我是工厂*/
class Factory {public static BaseProduct getProduct(String name){if ("A".equals(name)) {return new ProductA();}if ("B".equals(name)) {return new ProductB();}return new BaseProduct() {@Overridepublic String productName() {return "I am Base";}};}
}
(2)工厂三兄弟之工厂方法模式
刚才通过建造了一个工厂,通过用水来生产可乐与雪碧。随着企业的扩大,推出的产品越来越多,一个工厂生产更多不同的产品时,该工厂需要不断地调整。所以我们根据不同的产品推出了不同的工厂来专门生产某一个产品。
package com.example.demo.pattern.creational.factory.factorymethod;/*** 功能描述: 简单工厂模式** @author luxiaomeng* @date 2020/8/18 9:28* 修改日志: 暂无*/
public class FactoryMethodPattern {public static void main(String[] args) {BaseProduct product = new ProductA();System.out.println( product.productName());}
}/*** 产品规范-产品都得有名称*/
interface BaseProduct {String productName();
}/*** 我是橙汁*/
class ProductA implements BaseProduct {@Overridepublic String productName() {return "I am 橙汁";}
}/*** 我是可乐*/
class ProductB implements BaseProduct {@Overridepublic String productName() {return "I am 可乐";}
}/*** 工厂规范*/
interface BaseFactory {BaseProduct createProduct();
}/*** 橙汁工厂*/
class FactoryA implements BaseFactory{@Overridepublic BaseProduct createProduct() {return new ProductA();}
}
/*** 可乐工厂*/
class FactoryB implements BaseFactory{@Overridepublic BaseProduct createProduct() {return new ProductB();}
}
同样利用反射优化
config.xml
<?xml version="1.0" encoding="utf-8" ?>
<config><productName>com.example.demo.pattern.creational.factory.factorymethod.plus.FactoryA</productName>
</config>
package com.example.demo.pattern.creational.factory.factorymethod.plus;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;/*** 功能描述: 简单工厂模式** @author luxiaomeng* @date 2020/8/18 9:28* 修改日志: 暂无*/
public class FactoryMethodPattern {public static void main(String[] args) throws Exception {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dbf.newDocumentBuilder();Document doc = builder.parse(new File("E:\\WorkSpace\\IDEA\\study\\src\\main\\java\\com\\example\\demo\\pattern\\creational\\factory\\factorymethod\\plus\\config.xml"));NodeList nodeList = doc.getElementsByTagName("productName");Node classNode = nodeList.item(0).getFirstChild();String productName = classNode.getNodeValue().trim();Class<?> productFactory = Class.forName(productName);BaseFactory o = (BaseFactory) productFactory.newInstance();System.out.println(o.createProduct().productName());}
}/*** 产品规范-产品都得有名称*/
interface BaseProduct {String productName();
}/*** 我是橙汁*/
class ProductA implements BaseProduct {@Overridepublic String productName() {return "I am 橙汁";}
}/*** 我是可乐*/
class ProductB implements BaseProduct {@Overridepublic String productName() {return "I am 可乐";}
}/*** 工厂规范*/
interface BaseFactory {BaseProduct createProduct();}
/*** 橙汁工厂*/
class FactoryA implements BaseFactory {@Overridepublic BaseProduct createProduct() {return new ProductA();}
}
/*** 可乐工厂*/
class FactoryB implements BaseFactory {@Overridepublic BaseProduct createProduct() {return new ProductB();}
}
(3)工厂三兄弟之抽象工厂模式
package com.example.demo.pattern.creational.factory.abstractfactorypattern;/*** 功能描述: 工厂方法模式* 由于橙汁、可乐产品的火热,我们针对这两件产品分别建厂,利润大大增加。* 为了继续占领市场,我们又推出了无糖可乐,根据市场调查无糖可乐的市场需求并不大,* 单独建厂不太适合,但是为了满足小众需求,我们将该产品合并到可乐工厂* @author luxiaomeng* @date 2020/8/18 9:28* 修改日志: 暂无*/
public class AbstractFactoryPattern {public static void main(String[] args) {BaseProduct product = new ProductC();System.out.println( product.productName());}
}/*** 产品规范-产品都得有名称*/
interface BaseProduct {String productName();
}/*** 我是橙汁*/
class ProductA implements BaseProduct {@Overridepublic String productName() {return "I am 橙汁";}
}/*** 我是可乐*/
class ProductB implements BaseProduct {@Overridepublic String productName() {return "I am 可乐";}
}/*** 我是无糖可乐*/
class ProductC implements BaseProduct {@Overridepublic String productName() {return "I am 无糖可乐";}
}/*** 工厂规范*/
interface BaseFactory {BaseProduct createProduct(String args);
}/*** 橙汁工厂*/
class FactoryA implements BaseFactory{@Overridepublic BaseProduct createProduct(String args) {return new ProductA();}
}
/*** 可乐工厂*/
class FactoryB implements BaseFactory{@Overridepublic BaseProduct createProduct(String args) {if ("无糖".equals(args)) {return new ProductC();}return new ProductB();}
}
2.单例模式
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
单例模式有 3 个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点;
(1)懒汉式单例
public class LazySingleton
{//volatile:中文意为易变的,是java的一个关键字,volatile具有可见性、有序性,不具备原子性。//可见性:使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效private static volatile LazySingleton instance=null; //保证 instance 在所有线程中同步private LazySingleton(){} //private 避免类在外部被实例化public static synchronized LazySingleton getInstance(){//getInstance 方法前加同步if(instance==null){instance=new LazySingleton();}return instance;}
(2)饿汉式单例
public class HungrySingleton
{private static final HungrySingleton instance=new HungrySingleton();private HungrySingleton(){}public static HungrySingleton getInstance(){return instance;}
}
(3)IoDH
饿汉式单例类不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控 制烦琐,而且性能受影响。可见,无论是饿汉式单例还是懒汉式单例都存在这样那样的问 题,有没有一种方法,能够将两种单例的缺点都克服,而将两者的优点合二为一呢?答案 是:Yes!下面我们来学习这种更好的被称之为Initialization Demand Holder (IoDH)的技术。
/*** 功能描述: IoDH单例* 利用内部类的延时加载** @author luxiaomeng* @date 2020/8/18 15:26* 修改日志: 暂无*/
public class IoDHSingleton {private IoDHSingleton() {}private static class HolderClass {private final static IoDHSingleton instance = new IoDHSingleton();}public static IoDHSingleton getInstance() {return HolderClass.instance;}public static void main(String args[]) {IoDHSingleton s1, s2;s1 = IoDHSingleton.getInstance();s2 = IoDHSingleton.getInstance();System.out.println(s1 == s2);}
}
3.原型模式
原型设计模式:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
应用场景:
- 对象之间相同或相似,即只是个别的几个属性不同的时候。
- 对象的创建过程比较麻烦,但复制比较简单的时候。
(1)浅拷贝
模式的结构
原型模式包含以下主要角色。
- 抽象原型类:规定了具体原型对象必须实现的接口。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
原型类实现clone()方法,在clone方法中调用父类的clone()方法即可实现,但是只能拷贝基本数据类型
package com.example.demo.pattern.creational.prototype;/*** 功能描述: 原型模式-浅拷贝** @author luxiaomeng* @date 2020/8/18 15:46* 修改日志: 暂无*/
public class SunWuKong implements Cloneable{private String name = "孙悟空";private JinGuBang jinGuBang;public String getName() {return name;}public void setName(String name) {this.name = name;}public JinGuBang getJinGuBang() {return jinGuBang;}public void setJinGuBang(JinGuBang jinGuBang) {this.jinGuBang = jinGuBang;}public SunWuKong() {//1.从石头里蹦出来//2.取金箍棒//3.大闹天宫//。。。。。。。//总之,再创建一个孙悟空时太麻烦了。不如直接复制一个}/*** 于是孙悟空采用72变:实现java.lang包下的Cloneable接口,但实际实现调用的是Object.clone方法*/@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}public static void main(String[] args) throws CloneNotSupportedException {SunWuKong sunWuKong = new SunWuKong();JinGuBang jinGuBang = new JinGuBang();sunWuKong.setJinGuBang(jinGuBang);SunWuKong sixEar = (SunWuKong) sunWuKong.clone();System.out.println(sunWuKong==sixEar); //falseSystem.out.println(sunWuKong.jinGuBang==sixEar.jinGuBang); // true 可以看出孙悟空的金箍棒没有复制过来}
}
/*** 孙悟空的金箍棒*/
class JinGuBang {private String name="金箍棒";public String getName() {return name;}public void setName(String name) {this.name = name;}
}
(2)深拷贝
利用序列化来实现深拷贝,拿走猴哥的金箍棒
步骤:1)原型与引用类型实现Serializable
序列化接口
2)利用ObjectOutputStream
和ObjectInputStream
读取对象
package com.example.demo.pattern.creational.prototype.plus;import java.io.*;/*** 功能描述: 原型模式-浅拷贝** @author luxiaomeng* @date 2020/8/18 15:46* 修改日志: 暂无*/
public class SunWuKong implements Serializable {private String name = "孙悟空";private JinGuBang jinGuBang;public String getName() {return name;}public void setName(String name) {this.name = name;}public JinGuBang getJinGuBang() {return jinGuBang;}public void setJinGuBang(JinGuBang jinGuBang) {this.jinGuBang = jinGuBang;}public static void main(String[] args) throws IOException, ClassNotFoundException {SunWuKong sunWuKong = new SunWuKong();JinGuBang jinGuBang= new JinGuBang();sunWuKong.setJinGuBang(jinGuBang);ByteArrayOutputStream bao = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bao);oos.writeObject(sunWuKong);ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);SunWuKong liuer =(SunWuKong) ois.readObject();System.out.println(sunWuKong == liuer);System.out.println(sunWuKong.jinGuBang == liuer.jinGuBang);}
}/*** 孙悟空的金箍棒*/
class JinGuBang implements Serializable {private String name = "金箍棒";public String getName() {return name;}public void setName(String name) {this.name = name;}
}
4.建造者模式
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可 以创建不同的表示。建造者模式是一种对象创建型模式。
建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就 可以构建它们,用户不需要知道内部的具体构建细节
在建造者模式结构图中包含如下几个角色:
● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接 口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一 类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方 法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品 的内部表示并定义它的装配过程。
●Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽 象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装 配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建 造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
/*** 功能描述: 建造者模式* 假定要开发一个网站,该公司有两套方案,* 一、前端采用vue 后端采用java* 二、前端asp,后端.net** @author luxiaomeng* @date 2020/8/18 16:35* 修改日志: 暂无*/
public class Builder {public static void main(String[] args) {// 客户决定采用java开发JavaDever javaDever = new JavaDever();XiangMuZhuGuan xiangMuZhuGuan = new XiangMuZhuGuan();WebSite webSite = xiangMuZhuGuan.dev(javaDever);System.out.println(webSite.getFront()+"-"+webSite.getEnd());// 前端采用vue开发完成-后端采用Java开发完成}
}class WebSite {// 前端开发private String front;// 后端开发private String end;public String getFront() {return front;}public void setFront(String front) {this.front = front;}public String getEnd() {return end;}public void setEnd(String end) {this.end = end;}
}/*** 架构师*/
abstract class JiaGouShi {WebSite webSite = new WebSite();public abstract void buildFront();public abstract void buildEnd();public WebSite kaiFaWebSite() {return webSite;}
}/*** Java开发人员*/
class JavaDever extends JiaGouShi{@Overridepublic void buildFront() {webSite.setFront("前端采用vue开发完成");}@Overridepublic void buildEnd() {webSite.setEnd("后端采用Java开发完成");}
}/*** .net开发人员*/
class NetDever extends JiaGouShi {@Overridepublic void buildFront() {webSite.setFront("前端采用asp开发完成");}@Overridepublic void buildEnd() {webSite.setEnd("后端采用net开发完成");}
}/*** 项目主管*/
class XiangMuZhuGuan{public WebSite dev(JiaGouShi jiaGouShi) {jiaGouShi.buildFront();jiaGouShi.buildEnd();return jiaGouShi.kaiFaWebSite();}
}
5.适配器模式
适配器模式概述
与电源适配器相似,在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装 的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适 配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调 用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此, 适配器让那些由于接口不兼容而不能交互的类可以一起工作。
适配器模式可以将一个类的接口和另一个类的接口匹配起来,而无须修改原来的适配者接口 和抽象目标类接口。适配器模式定义如下:
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
(1)对象适配器模式
package com.example.demo.pattern.structural.adapter;/*** 功能描述: 对象适配器模式** @author luxiaomeng* @date 2020/8/19 13:42* 修改日志: 暂无*/
public class AdapterPattern {public static void main(String[] args) {LaptopPowerInterface laptopPower = new LaptopPowerAdapter();Integer power = laptopPower.getPower();System.out.println("笔记本电脑此时接口的电压为:"+power+"v");//笔记本电脑此时接口的电压为:20}
}/*** 适配者*/
class HomePower{private Integer power = 220;public Integer getPower() {return power;}
}/*** 抽象目标:笔记本电源接口*/
interface LaptopPowerInterface {public Integer getPower();
}
/**适配器:电源适配器*/
class LaptopPowerAdapter implements LaptopPowerInterface{private HomePower homePower;public LaptopPowerAdapter() {this.homePower = new HomePower();}/*** 削减电压为20V*/@Overridepublic Integer getPower() {return this.homePower.getPower()-200;}
}
(2)类适配器模式
package com.example.demo.pattern.structural.adapter.classasapter;/*** 功能描述: 类适配器模式** @author luxiaomeng* @date 2020/8/19 13:42* 修改日志: 暂无*/
public class AdapterPattern {public static void main(String[] args) {LaptopPowerInterface laptopPower = new LaptopPowerAdapter();Integer power = laptopPower.getPower();System.out.println("笔记本电脑此时接口的电压为:"+power+"v");//笔记本电脑此时接口的电压为:20}
}/*** 适配者*/
class HomePower{Integer power = 220;
}/*** 抽象目标:笔记本电源接口*/
interface LaptopPowerInterface {public Integer getPower();
}
/**适配器*/
class LaptopPowerAdapter extends HomePower implements LaptopPowerInterface{/*** 削减电压为20V*/@Overridepublic Integer getPower() {return super.power-200;}
}
(3)双向适配器模式
package com.example.demo.pattern.structural.adapter.twoway;/*** 功能描述: 双向适配器模式* 例子:充当协调者** @author luxiaomeng* @date 2020/8/19 13:42* 修改日志: 暂无*/
class Adapter implements Target, Adaptee { //同时维持对抽象目标类和适配者的引用 private Target target; private Adaptee adaptee;private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target;}public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}@Overridepublic void specificRequest() {target.request();}
}interface Target {public void request();
}interface Adaptee {public void specificRequest();
}
(4)缺省适配器模式
package com.example.demo.pattern.structural.adapter.defaultadapter;/*** 功能描述: 缺省适配器模式** @author luxiaomeng* @date 2020/8/19 13:42* 修改日志: 暂无*/
public class AdapterPattern {public static void main(String[] args) {PhonePower phonePower = new ChongDianBao();phonePower.typeC(); //我提供了typec手机的接口phonePower.mac(); // null}
}/*** 抽象目标 - 充电接口规范*/
interface PhonePower {public void typeC();public void mac();
}/** 抽象类*/
abstract class PowerAdapter implements PhonePower {@Overridepublic void typeC() {}@Overridepublic void mac() {}
}/*** 充电宝*/
class ChongDianBao extends PowerAdapter {@Overridepublic void typeC() {System.out.println("我提供了typec手机的接口");}}
6.桥接模式
桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维 度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职 责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构, 并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥 接模式。
桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承, 将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同 时有效控制了系统中类的个数。桥接定义如下:
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是 一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
桥接模式的结构与其名称一样,存在一条连接两个继承等级结构的桥,
桥接模式主要包含如下几个角色:
Abstraction:抽象类。
RefinedAbstraction:扩充抽象类。
Implementor:实现类接口。
ConcreteImplementor:具体实现类 。
package com.example.demo.pattern.structural.bridge;/*** 功能描述: 比如一个网游,有武当、少林门派的角色,角色又可以选择阵营(好,坏)** @author luxiaomeng* @date 2020/8/20 9:40* 修改日志: 暂无*/
public class BridgePattern {public static void main(String[] args) {//创建一个角色Role role = new WuDang();role.setMenPai(); //设置门派System.out.println(role.menPai);role.setZhenYing(new JiangHu());role.zhenYing.setZhenYing();/*** 您选择了武当派* 加入了江湖阵营*/}
}abstract class Role {// 门派public String menPai;public ZhenYing zhenYing;public void setZhenYing(ZhenYing zhenYing) {this.zhenYing = zhenYing;}public abstract void setMenPai();
}class WuDang extends Role {@Overridepublic void setMenPai() {this.menPai = "您选择了武当派";}
}class ShaoLing extends Role {@Overridepublic void setMenPai() {this.menPai = "您选择了少林";}
}/*** 阵营接口*/
interface ZhenYing {public void setZhenYing();
}/*** 江湖*/
class JiangHu implements ZhenYing {@Overridepublic void setZhenYing() {System.out.println("加入了江湖阵营");}
}/****/
class ChaoTing implements ZhenYing {@Overridepublic void setZhenYing() {System.out.println("加入了朝廷阵营");}
}
7.组合模式
组合模式概述
对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻 找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象)并调用执行,牵一而 动百,其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能 上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多 数情况下我们希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。 组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。
组合模式定义如下:
组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层 次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致 性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
在组合模式结构图中包含如下几个角色:
● Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口, 在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
● Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在 抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处 理。
● Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子 节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象 构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子 节点的业务方法。
package com.example.demo.pattern.structural.composite;import java.util.ArrayList;/*** 功能描述: 组合模式* 举例:给不同文件类型的文件杀毒** @author luxiaomeng* @date 2020/8/20 10:27* 修改日志: 暂无*/
public class CompositePattern {public static void main(String[] args) {AbstractFile file1, file2, file3, file4, folder1, folder2, folder3;folder1 = new Folder("Sunny的资料");folder2 = new Folder("图像文件");folder3 = new Folder("文本文件");file1 = new ImageFile("小龙女.jpg");file2 = new ImageFile("张无忌.gif");file3 = new TextFile("九阴真经.txt");file4 = new TextFile("葵花宝典.doc");folder2.add(file1);folder2.add(file2);folder3.add(file3);folder3.add(file4);folder1.add(folder2);folder1.add(folder3);folder1.killVirus();}
}//抽象文件类:抽象构件
abstract class AbstractFile {public abstract void add(AbstractFile file);public abstract void remove(AbstractFile file);public abstract AbstractFile getChild(int i);public abstract void killVirus();
}//图像文件类:叶子构件
class ImageFile extends AbstractFile {private String name;public ImageFile(String name) {this.name = name;}@Overridepublic void add(AbstractFile file) {System.out.println("对不起,不支持该方法!");}@Overridepublic void remove(AbstractFile file) {System.out.println("对不起,不支持该方法!");}@Overridepublic AbstractFile getChild(int i) {System.out.println("对不起,不支持该方法!");return null;}@Overridepublic void killVirus() {//模拟杀毒System.out.println("----对图像文件'" + name + "'进行杀毒");}
}//文本文件类:叶子构件
class TextFile extends AbstractFile {private String name;public TextFile(String name) {this.name = name;}@Overridepublic void add(AbstractFile file) {System.out.println("对不起,不支持该方法!");}@Overridepublic void remove(AbstractFile file) {System.out.println("对不起,不支持该方法!");}@Overridepublic AbstractFile getChild(int i) {System.out.println("对不起,不支持该方法!");return null;}@Overridepublic void killVirus() {//模拟杀毒System.out.println("----对文本文件'" + name + "'进行杀毒");}
}//文件夹类:容器构件
class Folder extends AbstractFile {//定义集合fileList,用于存储AbstractFile类型的成员 、 public Folder(String name) {private ArrayList<AbstractFile> fileList = new ArrayList<AbstractFile>();private String name;public Folder(String name) {this.name = name;}@Overridepublic void add(AbstractFile file) {fileList.add(file);}@Overridepublic void remove(AbstractFile file) {fileList.remove(file);}@Overridepublic AbstractFile getChild(int i) {return (AbstractFile) fileList.get(i);}@Overridepublic void killVirus() {System.out.println("****对文件夹'" + name + "'进行杀毒");for (Object obj : fileList) {((AbstractFile) obj).killVirus();}}
}
8.装饰者模式
装饰模式概述
装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为,在现实生活 中,这种情况也到处存在,例如一张照片,我们可以不改变照片本身,给它增加一个相框, 使得它具有防潮的功能,而且用户可以根据需要给它增加不同类型的相框,甚至可以在一个 小相框的外面再套一个大相框。
装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职 责,使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类,在装饰 类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。
装饰模式定义如下:
装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说, 装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
在装饰模式结构图中包含如下几个角色:
● Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实 现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对 象,实现客户端的透明操作。
● ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实 现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
● Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体 职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前 构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
● ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每 一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增 加新的方法用以扩充对象的行为。
package com.example.demo.pattern.structural.decorator;/*** 功能描述: 装饰模式* 例子:魅族17ota屏幕刷新率** @author luxiaomeng* @date 2020/8/21 10:05* 修改日志: 暂无*/
public class DecoratorPattern {public static void main(String[] args) {Meizu17 meizu17 = new Meizu17();OtaDecorator ota = new OtaDecorator(meizu17);ota.screenreFreshRate();// 90HZ屏幕选项//120hz屏幕选项}
}/*** 抽象类构建*/
abstract class Phone{public abstract void screenreFreshRate();
}/*** 具体构件类*/
class Meizu17 extends Phone {@Overridepublic void screenreFreshRate() {System.out.println("90HZ屏幕选项");}
}/*** 构件装饰类*/
class OtaDecorator extends Phone {private Phone phone;public OtaDecorator(Phone phone) {this.phone = phone;}@Overridepublic void screenreFreshRate() {phone.screenreFreshRate();System.out.println("120hz屏幕选项");}
}
9.外观模式
外观模式定义如下: 外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义 了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式包含如下两个角色:
(1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个 或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应 的子系统去,传递给相应的子系统对象处理。
(2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统 可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被 客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外 观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
package com.example.demo.pattern.structural.facade;/*** 功能描述: 外观模式(该类就是个外观角色)* 角色:外观角色,子系统角色* 例子: 蜜雪冰城门面中,一个销售(外观角色),一个准备材料,一个制作* @author luxiaomeng* @date 2020/8/24 16:19* 修改日志: 暂无*/
public class FacadePattern {A a = new A();B b = new B();void sale() {a.prepare();b.make();System.out.println("拿给买家");}public static void main(String[] args) {FacadePattern fp = new FacadePattern();fp.sale();//我在准备材料//我在制作//拿给买家}}interface Sale {void saleDrink();
}class A {void prepare() {System.out.println("我在准备材料");}
}
class B {void make () {System.out.println("我在制作");}
}
10.享元模式
当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等 问题。例如在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象 来表示,将会占用较多的内存空间,那么我们如何去避免系统中出现大量相同或相似的对 象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?享元模式正为解决 这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出 现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以 出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这 些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个 享元对象,将其放在享元池中,需要时再从享元池取出。
享元模式定义如下:
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使
用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于 享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种 对象结构型模式。
package com.example.demo.pattern.structural.flyweight;import java.util.Hashtable;/*** 功能描述: 享元模式* 例子: 围棋盘上,黑白棋子的复用** @author luxiaomeng* @date 2020/8/24 16:46* 修改日志: 暂无*/
public class FlyWeightPattern {public static void main(String[] args) {IgoChessman black1, black2, black3, white1, white2;IgoChessmanFactory factory;//获取享元工厂对象factory = IgoChessmanFactory.getInstance();//通过享元工厂获取三颗黑子black1 = IgoChessmanFactory.getIgoChessman("b");black2 = IgoChessmanFactory.getIgoChessman("b");black3 = IgoChessmanFactory.getIgoChessman("b");System.out.println("判断两颗黑子是否相同:" + (black1 == black2));//通过享元工厂获取两颗白子white1 = IgoChessmanFactory.getIgoChessman("w");white2 = IgoChessmanFactory.getIgoChessman("w");System.out.println("判断两颗白子是否相同:" + (white1 == white2)); //显示棋子,同时设置棋子的坐标位置black1.display(new Coordinates(1, 2));black2.display(new Coordinates(3, 4));black3.display(new Coordinates(1, 3));white1.display(new Coordinates(2, 5));white2.display(new Coordinates(2, 4));}
}//坐标类:外部状态类
class Coordinates {private int x;private int y;public Coordinates(int x, int y) {this.x = x;this.y = y;}public int getX() {return this.x;}public void setX(int x) {this.x = x;}public int getY() {return this.y;}public void setY(int y) {this.y = y;}
}class IgoChessmanFactory {private static IgoChessmanFactory instance = new IgoChessmanFactory();private static Hashtable ht; //使用Hashtable来存储享元对象,充当享元池private IgoChessmanFactory() {ht = new Hashtable();IgoChessman black, white;black = new BlackIgoChessman();ht.put("b", black);white = new WhiteIgoChessman();ht.put("w", white);}//返回享元工厂类的唯一实例public static IgoChessmanFactory getInstance() {return instance;}//通过key来获取存储在Hashtable中的享元对象public static IgoChessman getIgoChessman(String color) {return (IgoChessman) ht.get(color);}
}//围棋棋子类:抽象享元类
abstract class IgoChessman {public abstract String getColor();public void display(Coordinates coord){System.out.println("棋子颜色:" + this.getColor() + ",棋子位置:" + coord.getX() + "," + coord.getY()); }
}//黑色棋子类:具体享元类
class BlackIgoChessman extends IgoChessman {@Overridepublic String getColor() {return "黑色";}
}//白色棋子类:具体享元类
class WhiteIgoChessman extends IgoChessman {@Overridepublic String getColor() {return "白色";}
}
11.代理模式
代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。代理模式是一种对象结构型模式。在代理模式中引入了一个新的代理对象,代理对象在客户 端对象和目标对象之间起到中介的作用,它去掉客户不能看到的内容和服务或者增添客户需 要的额外的新服务。
(1) Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使 用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
(2) Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题 对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代 真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实 主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所 引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中 的操作。
(3) RealSubject(真实主题角色):它定义了代理角色所代表的真实对象,在真实主题角色中 实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操 作
(1)静态代理
package com.example.demo.pattern.structural.proxy.staticproxy;/*** 功能描述: 用中介租房流程实现静态代理* 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)* 角色: 顾客-》被代理类* 中介-》代理类* 接口* @author luxiaomeng* @date 2020/8/13 16:05* 修改日志: 暂无*/
public class RentingHouseDemo {public static void main(String[] args) {// 张三想租房子Customer customer = new Customer("张三");// 中介大姐Agent agent = new Agent(customer);agent.signContract();/**输出结果:* 中介:正在找房子* 张三租到了房子* 中介:给我钱*/}
}/*** 租房业务*/
interface RentingHouse {//签订租房合同void signContract();
}/*** 客户*/
class Customer implements RentingHouse {private String name;public Customer(String name) {this.name = name;}@Overridepublic void signContract() {System.out.println(this.name + "租到了房子");}
}/*** 中介*/
class Agent implements RentingHouse {Customer customer;//找我就给他办事public Agent(Customer customer) {this.customer = customer;}//我们中介是这样干租房业务的@Overridepublic void signContract() {findHouse();this.customer.signContract();giveMeMoney();}public void findHouse() {System.out.println("中介:正在找房子");}public void giveMeMoney() {System.out.println("中介:收取中介费");}
}
(2)动态代理
1️⃣ jdk实现动态代理
package com.example.demo.pattern.structural.proxy.dynamic;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 功能描述: 以租房案例实现jdk的动态代理* 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)* 角色: 顾客-》被代理类* 中介-》代理类* 接口* @author luxiaomeng* @date 2020/8/13 16:45* 修改日志: 暂无*/
public class DynamicProxy {public static void main(String[] args) {// 张三想租房子Customer customer = new Customer("张三");Handler handler = new Handler(customer);RentingHouse o = (RentingHouse)Proxy.newProxyInstance(customer.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);o.signContract();}
}/*** 租房业务*/
interface RentingHouse {//签订租房合同void signContract();
}/*** 客户1123132*/
class Customer implements RentingHouse {private String name;public Customer(String name) {this.name = name;}@Overridepublic void signContract() {System.out.println(this.name + "租到了房子");}
}/*** 调用处理器*/
class Handler implements InvocationHandler{Object object;//找我就给他办事public Handler(Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {findHouse();Object returnValue = method.invoke(object, args);giveMeMoney();return returnValue;}public void findHouse() {System.out.println("中介:正在找房子");}public void giveMeMoney() {System.out.println("中介:收取中介费");}
}
2️⃣ CGLIB实现动态代理
package com.example.demo.pattern.structural.proxy.dynamic.cglib;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** 功能描述: 以租房案例实现jdk的动态代理* 中介租房流程: 找房源(中介)-签合同-收取中介费(中介)* 角色: 顾客-》被代理类* 中介-》代理类* 接口* @author luxiaomeng* @date 2020/8/14 14:46* 修改日志: 暂无*/
public class DynamicProxy {public static void main(String[] args) {// 通过CGLIB动态代理获取代理对象的过程Enhancer enhancer = new Enhancer();// 设置enhancer对象的父类enhancer.setSuperclass(Customer.class);// 设置enhancer的回调对象enhancer.setCallback(new Handler());// 创建代理对象Customer proxy= (Customer)enhancer.create();proxy.signContract();}}/*** 客户*/
class Customer {private String name;public void signContract() {System.out.println( "租到了房子");}
}/*** 调用处理器*/
class Handler implements MethodInterceptor {public void findHouse() {System.out.println("中介:正在找房子");}public void giveMeMoney() {System.out.println("中介:收取中介费");}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {findHouse();Object invoke = methodProxy.invokeSuper(o, objects);giveMeMoney();return invoke;}
}
12.责任链模式
职责链模式定义如下:职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者 耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传 递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。
在职责链模式结构图中包含如下几个角色:
● Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的 具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者 的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图 中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。
● ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理 者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是 否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理 者中可以访问链中下一个对象,以便请求的转发。
在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这 个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上 的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织 链和分配责任
package com.example.demo.pattern.behavioral.chain;/*** 功能描述: 责任链模式* 例子:富士康工厂生产手机 A负责装配,B负责贴膜,C负责测试 必须按ABC的顺序来* @author luxiaomeng* @date 2020/8/25 13:52* 修改日志: 暂无*/
public class ChainOfResponsibility {public static void main(String[] args) {// 创建手机Phone phone = new Phone();// 创建责任链Handler a = new A();Handler b = new B();Handler c = new C();a.setNext(b);b.setNext(c);a.work(phone);//A组装了手机//B贴了膜//C进行了测试//手机制造完成}
}class Phone {// 状态 1组装 2已贴膜 3已测试private int status =0;public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}
}/*** 抽象处理类*/
abstract class Handler {protected Handler next;public abstract void work(Phone phone);public Handler getNext() {return next;}public void setNext(Handler next) {this.next = next;}
}class A extends Handler {@Overridepublic void work(Phone phone) {if (phone.getStatus() == 0) {System.out.println("A组装了手机");phone.setStatus(1);next.work(phone);}}
}
class B extends Handler {@Overridepublic void work(Phone phone) {if (phone.getStatus() == 1) {System.out.println("B贴了膜");phone.setStatus(2);next.work(phone);}}
}
class C extends Handler {@Overridepublic void work(Phone phone) {if (phone.getStatus() == 2) {System.out.println("C进行了测试");phone.setStatus(3);System.out.println("手机制造完成");}}
}
13.命令模式
命令模式(CommandPattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
package com.example.demo.pattern.behavioral.command;/*** 功能描述: 命令模式* 案例:简易加法计算器** @author luxiaomeng* @date 2020/8/26 9:54* 修改日志: 暂无*/
public class CommandPattern {public static void main(String[] args) {CalculatorForm calculatorForm = new CalculatorForm();AbstractCommand command = new ConcreteCommand();calculatorForm.setCommand(command);calculatorForm.compute(10);calculatorForm.undo();}
}// 加法类:请求接收者
class Adder {private int num =0;//定义初始值为0//加法操作,每次讲传入的值与num作加法运算,并返回结果public int add(int value) {num += value;return num;}
}// 抽象命令类
abstract class AbstractCommand {public abstract int execute(int value);//声明命令执行方法public abstract int undo();//声明命令撤销方法
}
// 具体命令类
class ConcreteCommand extends AbstractCommand {private Adder adder = new Adder();private int value;// 加法操作@Overridepublic int execute(int value) {this.value = value;return adder.add(value);}// 撤销操作@Overridepublic int undo() {return adder.add(-value);}
}// 计算器界面类:请求发送者
class CalculatorForm {private AbstractCommand command;public void setCommand(AbstractCommand abstractCommand) {this.command = abstractCommand;}public void compute(int value) {int i = command.execute(value);System.out.println("执行运算-运算结果为:" + i);}public void undo() {int i = command.undo();System.out.println("执行撤销,运算结果为:"+i);}
}
14.解释器模式
解释器模式概述
解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向 对象语言构成一个简单的语言解释器。在某些情况下,为了更好地描述某一些特定类型的问 题,我们可以创建一种新的语言,这种语言拥有自己的表达式和结构,即文法规则,这些问 题的实例将对应为该语言中的句子。此时,可以使用解释器模式来设计这种新的语言。对解 释器模式的学习能够加深我们对面向对象思想的理解,并且掌握编程语言中文法规则的解释 过程。
解释器模式定义如下:解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个 解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
在解释器模式结构图中包含如下几个角色:
● AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结 符表达式和非终结符表达式的公共父类。
● TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法 中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个 解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为 复杂的句子。
● NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实 现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以 继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
● Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通 常它临时存储了需要解释的语句。
package com.example.demo.pattern.behavioral.interpreter;
import java.util.*;
/*** 功能描述: 解释器模式* 例子:输入一组表达式,判断上车的乘客是否收费,如果是本地的老人妇女儿童不收费*<expression> ::= <city>的<person>* <city> ::= 本地|外地* <person> ::= 老人|妇女|儿童* @author luxiaomeng* @date 2020/8/26 10:39* 修改日志: 暂无*/
public class InterpreterPattern {public static void main(String[] args) {Context bus=new Context();bus.freeRide("本地的老人");bus.freeRide("外地的年轻人");bus.freeRide("本地的妇女");bus.freeRide("外地的儿童");bus.freeRide("本地的儿童");}
}
//抽象表达式类
interface Expression
{public boolean interpret(String info);
}
//终结符表达式类
class TerminalExpression implements Expression
{private Set<String> set= new HashSet<String>();public TerminalExpression(String[] data){for(int i=0;i<data.length;i++) {set.add(data[i]);}}@Overridepublic boolean interpret(String info){if(set.contains(info)){return true;}return false;}
}
//非终结符表达式类
class AndExpression implements Expression
{private Expression city=null;private Expression person=null;public AndExpression(Expression city,Expression person){this.city=city;this.person=person;}@Overridepublic boolean interpret(String info){String s[]=info.split("的");return city.interpret(s[0])&&person.interpret(s[1]);}
}
//环境类
class Context
{private String[] citys={"本地"};private String[] persons={"老人","妇女","儿童"};private Expression cityPerson;public Context(){Expression city=new TerminalExpression(citys);Expression person=new TerminalExpression(persons);cityPerson=new AndExpression(city,person);}public void freeRide(String info){boolean ok=cityPerson.interpret(info);if(ok) {System.out.println("您是"+info+",您本次乘车免费!");} else {System.out.println(info+",您不是免费人员,本次乘车扣费2元!");}}
}
15.迭代器模式
迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表 示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
在迭代器模式结构图中包含如下几个角色:
● Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是 否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器 中将实现这些方法。
● ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时 在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是 一个表示位置的非负整数。
● Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于 创建一个迭代器对象,充当抽象迭代器工厂角色
● ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该 方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。
package com.example.demo.pattern.behavioral;import java.util.ArrayList;
import java.util.List;/*** 功能描述: 迭代器模式* 例子:类似于jdk集合中的迭代器** @author luxiaomeng* @date 2020/8/27 9:10* 修改日志: 暂无*/
public class IteratorPattern {public static void main(String[] args) {List products = new ArrayList();products.add("奶茶");products.add("咖啡");products.add("牛奶");AbstractObjectList list;AbstractIterator iterator;list = new ProductList(products);iterator = list.createIterator();System.out.println("正向遍历");while (!iterator.isLast()) {System.out.println(iterator.getNextItem());iterator.next();}}
}// 抽象聚合类
abstract class AbstractObjectList {protected List<Object> objects = new ArrayList<>();public AbstractObjectList(List objects) {this.objects = objects;}public void addObject(Object object) {this.objects.add(object);}public void removeObject(Object object) {this.objects.remove(object);}public List getObjects() {return this.objects;}//声明创建迭代器对象的抽象工厂方法public abstract AbstractIterator createIterator();
}class ProductList extends AbstractObjectList {public ProductList(List objects) {super(objects);}@Overridepublic AbstractIterator createIterator() {return new ProductIterator(this);}}// 抽象迭代器
interface AbstractIterator {public void next();public boolean isLast();public void previous();public boolean isFirst();public Object getNextItem();public Object getPreviousItem();
}//商品迭代器:具体迭代器
class ProductIterator implements AbstractIterator {private ProductList productList;private List products;private int cursor1; //定义一个游标,用于记录正向遍历的位置private int cursor2; //定义一个游标,用于记录逆向遍历的位置public ProductIterator(ProductList list) {this.productList = list;this.products = list.getObjects();cursor1 = 0;cursor2 = products.size() - 1;}@Overridepublic void next() {if (cursor1 < products.size()) {cursor1++;}}@Overridepublic boolean isLast() {return (cursor1 == products.size());}@Overridepublic void previous() {if (cursor2 > -1) {cursor2--;}}@Overridepublic boolean isFirst() {return (cursor2 == -1);}@Overridepublic Object getNextItem() {return products.get(cursor1);}@Overridepublic Object getPreviousItem() {return products.get(cursor2);}
}
16.中介者模式
中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中 介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之 间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现 协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类 实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他 同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同 事类中实现了在抽象同事类中声明的抽象方法
package com.example.demo.pattern.behavioral.mediator;import java.util.HashMap;
import java.util.Map;/*** 功能描述: 中介者模式* 业务场景: 平常写信需要记录对方的地址,我们用了QQ以后,服务器来维护这种关系* 模拟发消息 B -A A -B* @author luxiaomeng* @date 2020/9/4 11:58* 修改日志: 暂无*/
public class MediatorPattern {public static void main(String[] args) {A a =new A();B b = new B();TencentServer tencentServer = new TencentServer();tencentServer.setUser(a);tencentServer.setUser(b);a.sendMessageToServer(tencentServer);b.sendMessageToServer(tencentServer);}
}abstract class User {String qqId;String name;public abstract void sendMessageToServer(Server server);
}interface Server {public void sendMessage(String sendUserQQ,String receiveUserQQ);
}class TencentServer implements Server {Map<String ,User> map = new HashMap();public void setUser(User user) {map.put(user.qqId, user);System.out.println(user.name+"上线了");}@Overridepublic void sendMessage(String sendUserQQ,String receiveUserQQ) {System.out.println(map.get(sendUserQQ).name+"给"+map.get(receiveUserQQ).name+"发消息");}
}class A extends User {public A() {this.qqId = "8888";this.name = "张三";}@Overridepublic void sendMessageToServer(Server server) {server.sendMessage(this.qqId,"9999");}
}
class B extends User {public B() {this.qqId = "9999";this.name = "李四";}@Overridepublic void sendMessageToServer(Server server) {server.sendMessage(this.qqId,"8888");}
}
17.备忘录模式
备忘录模式定义:
备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在 该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对 象行为型模式,其别名为Token。
角色:
●Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
●Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录 的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是, 除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同 的编程语言中实现机制会有所不同。
●Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容 进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不 能修改对象,也无须知道对象的实现细节。
package com.example.demo.pattern.behavioral.memento;import javax.persistence.criteria.CriteriaBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;/*** 功能描述: 备忘录模式* 模拟一下编程工具的撤销功能吧** @author luxiaomeng* @date 2020/9/4 14:42* 修改日志: 暂无*/
public class MementoPattern {public static void main(String[] args) {// 撤销管理对象Caretaker caretaker = new Caretaker();InputText inputText = new InputText();inputText.setText("public");caretaker.add(inputText.save());inputText.setText("public void");caretaker.add(inputText.save());inputText.setText("public void main");// 展示当前内容System.out.println(inputText.getText());// 开始撤销inputText.restore(caretaker.get());System.out.println(inputText.getText());// 再次撤销inputText.restore(caretaker.get());System.out.println(inputText.getText());//public void main//public void//public}}class InputText {private String text;public String getText() {return text;}public void setText(String text) {this.text = text;}public CheXiao save() {return new CheXiao(this.text);}public void restore(CheXiao cheXiao) {this.text = cheXiao.getText();}
}/*** 撤销键*/
class CheXiao {private String text;public CheXiao(String text) {this.text = text;}public String getText() {return text;}public void setText(String text) {this.text = text;}
}class Caretaker {private Stack<CheXiao> list = new Stack<>();public void add(CheXiao cheXiao) {list.push(cheXiao);}public CheXiao get() {return list.pop();}
}
18.观察者模式
观察者模式定义如下:观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系, 使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式 的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器 (Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
在观察者模式结构图中包含如下几个角色:
● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集 合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察 者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数 据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义 的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接 口声明了更新数据的方法update(),因此又称为抽象观察者。
● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它 存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观 察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自 己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
package com.example.demo.pattern.behavioral.observer;import java.util.ArrayList;/*** 功能描述: 观察者模式* 描述:创建金庸群侠战队,某一个成员遭受攻击,别的成员去救援** @author luxiaomeng* @date 2020/9/7 10:18* 修改日志: 暂无*/
public class ObserverPattern {public static void main(String[] args) {// 定义观察目标对象BaseAllyControlCenter acc;acc = new ConcreteAllyControlCenter("金庸群侠");
// 定义四个观察者对象Observer player1, player2, player3, player4;player1 = new Player("杨过");acc.join(player1);player2 = new Player("令狐冲");acc.join(player2);player3 = new Player("张无忌");acc.join(player3);player4 = new Player("段誉");acc.join(player4);
// 某成员遭受攻击player1.beAttacked(acc);}
}//抽象观察类
interface Observer {public String getName();public void setName(String name);public void help();//声明支援盟友方法public void beAttacked(BaseAllyControlCenter acc);//声明遭受攻击方法
}//战队成员类:具体观察者类
class Player implements Observer {private String name;public Player(String name) {this.name = name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic String getName() {return this.name;}//支援盟友方法的实现@Overridepublic void help() {System.out.println("坚持住," + this.name + "来救你!");}//遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知@Overridepublic void beAttacked(BaseAllyControlCenter acc) {System.out.println(this.name + "被攻击!");acc.notifyObserver(name);}
}//战队控制中心类:目标类
abstract class BaseAllyControlCenter {protected String allyName; //战队名称protected ArrayList<Observer> players = new ArrayList<Observer>();public void setAllyName(String allyName) {this.allyName = allyName;}public String getAllyName() {return this.allyName;}//注册方法public void join(Observer obs) {System.out.println(obs.getName() + "加入" + this.allyName + "战队!");players.add(obs);}//注销方法public void quit(Observer obs) {System.out.println(obs.getName() + "退出" + this.allyName + "战队!");players.remove(obs);}//声明抽象通知方法public abstract void notifyObserver(String name);
}//具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends BaseAllyControlCenter {public ConcreteAllyControlCenter(String allyName) {System.out.println(allyName + "战队组建成功!");System.out.println("----------------------------");this.allyName = allyName;}//实现通知方法@Overridepublic void notifyObserver(String name) {System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击");//遍历观察者集合,调用每一个盟友(自己除外)的支援方法for (Object obs : players) {if (!((Observer) obs).getName().equalsIgnoreCase(name)) {((Observer) obs).help();}}}
}
19.状态模式
状态模式定义如下
状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修 改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
● Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状 态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态 类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时, 它是一个State子类的对象。
● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在 抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状 态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写 在抽象状态类中。
● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一 个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为 有所不同。
package com.example.demo.pattern.behavioral.state;/*** 功能描述: 状态模式* 例子: 比如一个角色,拥有 人,恶魔,天使,三种状态,并对应三种不同的技能* @author luxiaomeng* @date 2020/9/7 10:52* 修改日志: 暂无*/
public class StatePattern {public static void main(String[] args) {Role role = new Role();AngelState as = new AngelState();DevilState ds = new DevilState();PersonState ps = new PersonState();as.doAction(role);System.out.println("
23种设计模式模式笔记+易懂案例相关推荐
- 23种设计模式-个人笔记(二)
目录 五.23 种设计模式 1.单例模式 1.1.单例模式的定义与特点 1.2.单例模式的优点和缺点 1.3.单例模式的应用场景 1.4.单例模式的结构与实现 1.5.八种方式详解 1.6.单例模式在 ...
- 23种设计模式-个人笔记(一)
目录 一.认识设计模式 1.软件设计模式的概念与意义 1.1.软件设计模式的概念 1.2.学习设计模式的意义 2.设计模式的目的 3.什么是设计模式的原则 4.掌握设计模式的层次 5.软件设计模式的基 ...
- 23种设计模式-个人笔记(三)
目录 行为型模式 12.模板方法模式 12.1.模式的定义与特点 12.2.模式的结构与实现 12.3.模板方法模式的钩子方法 12.4.模板方法模式在Spring框架应用的源码分析 12.5.模板方 ...
- 23种设计模式总结及应用案例
设计模式,七大原则 开闭原则 对扩展开放(提供方),对修改关闭(使用方). 抽象提供方的方法,调用方传入抽象类的子类实现,提供方调用子类方法完成具体实现 里氏替换原则 所有引用基类的地方都必须能透明的 ...
- 详解23种设计模式(基于Java)—— 结构型模式(三 / 五)
目录 3.结构型模式(7种) 3.1.代理模式 3.1.1.概述 3.1.2.结构 3.1.3.静态代理 3.1.4.JDK动态代理 3.1.5.CGLIB动态代理 3.1.6.三种代理的对比 3.1 ...
- 23种设计模式之单例模式、工厂模式、原型模式、建造者模式
系列文章目录 第一章:程序设计原则-单一职责.接口隔离.依赖倒置.里式替换 第二章:程序设计原则-开闭原则.迪米特法则.合成复用原则 文章目录 系列文章目录 一.设计模式简单介绍 1.1.什么是设计模 ...
- 23种设计模式学习记录之代理模式
想说的话: 在大学的时候曾经学过这23种设计模式,但是那时没啥编程经验,糊里糊涂过了一遍,没多久就忘记了,工作之后将精力主要集中在学习新技术上,比如springboot,cloud,docker,vu ...
- 备战面试日记(3.4) - (设计模式.23种设计模式之行为型模式)
本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.12 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文 ...
- 23种设计模式7_代理模式之一静态代理
23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...
最新文章
- GBDT原理与泰勒展开
- Spring 注解AOP
- 【Redis学习笔记】2018-06-12 复制与传播
- 解决windows找不到D:launcher\launcher.exe的方法
- mysql deadlock found when trying to get lock 问题排查
- 【转】js日期时间函数
- 只删除字符串前面的‘*’号。
- linux 命令行管理,Linux命令行界面下的用户和组的管理
- Atitit.jquery 版本新特性attilax总结
- 全志平台BSP裁剪(2)附件一 General setup配置说明
- 用户故事,史诗故事和主题故事
- 增加Java项目经验
- 逻辑门图解(NOT门 AND门 OR门 XOR门)
- 【AJAX 教程】JS 原生 AJAX 请求
- 惊呆了,我们的加密视频教学竟然可以轻易翻录和破解!!!
- 中国塑料加工工业协会侵犯群益公司名誉权 法院判决赔偿财产损失和赔礼道歉30天
- python制作时间,如何利用python制作时间戳转换工具详解
- 通过将OC编译成C++ 一探究竟(边学编写,帮忙点评)
- python爬取今日头条专栏_[python3]今日头条图片爬取
- 小伙获25位美国总统签名 价值数百万(图)
热门文章