applicationContext.xml<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="userMapper" class="com.spring.mapper.impl.UserMapperImpl"> <property name="name" value="孙笑川"/> <property name="password" value="123456"/> </bean> <bean id="userService" class="com.spring.service.impl.UserServiceImpl"> <property name="userMapper" ref="userMapper"/> </bean> </beans>1. pojo（1）PropertyValue类用于封装bean的属性public class PropertyValue { /** * name */ private String name; /** * ref */ private String ref; /** * value:给基本数据类型及String类型赋的值 */ private String value; public PropertyValue() { } public PropertyValue(String name, String ref, String value) { this.name = name; this.ref = ref; this.value = value; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }（2）MutablePropertyValues类一个bean标签可以有多个 property 子标签，该类用于存储并管理多个 Propertyvalue 对象public class MutablePropertyValues implements Iterable<PropertyValue> { private final List<PropertyValue> propertyValueList; public MutablePropertyValues() { this.propertyValueList = new ArrayList<>(); } public MutablePropertyValues(List<PropertyValue> propertyValueList) { if (propertyValueList == null) { this.propertyValueList = new ArrayList<>(); } else { this.propertyValueList = propertyValueList; } } /** * 获取PropertyValue数组 * * @return */ public PropertyValue[] getPropertyValues() { return propertyValueList.toArray(new PropertyValue[0]); } /** * 根据名称获取PropertyValue对象 * * @param propertyName * @return */ public PropertyValue getPropertyValueByName(String propertyName) { for (PropertyValue propertyValue : propertyValueList) { if (propertyValue.getName().equals(propertyValue)) { return propertyValue; } } return null; } /** * 判断集合是否为空 * * @return */ public boolean isEmpty() { return propertyValueList.isEmpty(); } /** * 添加 * * @param propertyValue * @return */ public MutablePropertyValues addPropertyValue(PropertyValue propertyValue) { for (int i = 0; i < propertyValueList.size(); i++) { PropertyValue currentPropertyValue = this.propertyValueList.get(i); if (currentPropertyValue.getName().equals(propertyValue.getName())) { propertyValueList.set(i, new PropertyValue(propertyValue.getName(), propertyValue.getRef(), propertyValue.getValue())); return this; } } this.propertyValueList.add(propertyValue); return this; } /** * 判断是否包含指定名称的PropertyValue对象 * * @param propertyName * @return */ public boolean contains(String propertyName) { return this.getPropertyValueByName(propertyName) != null; } /** * 获取迭代器对象 * * @return */ @Override public Iterator<PropertyValue> iterator() { return propertyValueList.listIterator(); } } （3）BeanDefinitionBeanDefinition 用来封装 bean 的信息，主要包含id（bean对象的名称）、class（需交由 spring 管理的类的全路径类名）、子标签 property 数据public class BeanDefinition { private String id; private String className; private MutablePropertyValues propertyValues; public BeanDefinition() { propertyValues = new MutablePropertyValues(); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public MutablePropertyValues getPropertyValues() { return propertyValues; } public void setPropertyValues(MutablePropertyValues propertyValues) { this.propertyValues = propertyValues; } }2. 注册表（1）BeanDefinitionRegistry接口注册 BeanDefinition 对象到注册表中从注册表中删除指定名称的对象根据名称获取指定对象根据名称判断是否包含指定对象获取已注册 bean 的个数获取已注册 bean 的名称数组 public interface BeanDefinitionRegistry { /** * 注册BeanDefinition对象到注册表中 * * @param beanName * @param beanDefinition */ void registerBeanDefinition(String beanName, BeanDefinition beanDefinition); /** * 从注册表中删除指定名称的对象 * * @param beanName */ void removeBeanDefinition(String beanName); /** * 根据名称获取指定对象 * * @param beanName * @return */ BeanDefinition getBeanDefinition(String beanName); /** * 根据名称判断是否包含指定对象 * * @param beanName * @return */ boolean containsBeanDefinition(String beanName); /** * 获取已注册bean的个数 * * @return */ int getBeanDefinitionCount(); /** * 获取已注册bean的名称数组 * * @return */ String[] getBeanDefinitionNames(); }（2）SimpleBeanDefinitionRegistry类该类实现了 BeanDefinitionRegistry 接口，并定义Map集合作为注册表容器public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry { /** * BeanDefinition存储容器 */ private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { beanDefinitionMap.put(beanName, beanDefinition); } @Override public void removeBeanDefinition(String beanName) { beanDefinitionMap.remove(beanName); } @Override public BeanDefinition getBeanDefinition(String beanName) { return beanDefinitionMap.get(beanName); } @Override public boolean containsBeanDefinition(String beanName) { return beanDefinitionMap.containsKey(beanName); } @Override public int getBeanDefinitionCount() { return beanDefinitionMap.size(); } @Override public String[] getBeanDefinitionNames() { return beanDefinitionMap.keySet().toArray(new String[0]); } }3. 解析器（1）BeanDefinitionReader接口用于解析配置文件并在注册表中注册bean的信息：获取注册表功能，让外界可以通过此对象获取注册表对象加载配置文件，并注册bean数据 public interface BeanDefinitionReader { /** * 获取注册表对象 * * @return */ BeanDefinitionRegistry getRegistry(); /** * 加载配置文件并在注册表中注册 * * @param configLocation */ void loadBeanDefinitions(String configLocation) throws DocumentException; }（2）XmlBeanDefinitionReader类用于解析xml配置文件，该类实现了 BeanDefinitionReader 接口public class XmlBeanDefinitionReader implements BeanDefinitionReader { /** * 声明注册表对象 */ private BeanDefinitionRegistry registry; public XmlBeanDefinitionReader() { registry = new SimpleBeanDefinitionRegistry(); } @Override public BeanDefinitionRegistry getRegistry() { return registry; } @Override public void loadBeanDefinitions(String configLocation) throws DocumentException { SAXReader reader = new SAXReader(); //获取类路径下的配置文件 InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation); Document document = reader.read(is); //根标签 Element rootElement = document.getRootElement(); //根标签下的bean标签对象 List<Element> beanElementList = rootElement.elements(); for (Element beanElement : beanElementList) { //id String id = beanElement.attributeValue("id"); //class String className = beanElement.attributeValue("class"); MutablePropertyValues propertyValues = new MutablePropertyValues(); //property List<Element> propertyList = beanElement.elements("property"); for (Element propertyElement : propertyList) { String name = propertyElement.attributeValue("name"); String ref = propertyElement.attributeValue("ref"); String value = propertyElement.attributeValue("value"); propertyValues.addPropertyValue(new PropertyValue(name, ref, value)); } //封装 BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setId(id); beanDefinition.setClassName(className); beanDefinition.setPropertyValues(propertyValues); //将beanDefinition注册到注册表中 registry.registerBeanDefinition(id, beanDefinition); } } }4. IOC容器（1）BeanFactory接口在该接口中定义IOC容器的统一规范（即获取 bean 对象）public interface BeanFactory { /** * 根据名称获取bean * * @param name * @return */ Object getBean(String name) throws Exception; /** * 根据名称、class类获取bean * * @param name * @param clazz * @param <T> * @return */ <T> T getBean(String name, Class<? extends T> clazz) throws Exception; }（2）ApplicationContext接口该接口的所有子实现类对 bean 对象的创建都是非延时的，所以在该接口中定义 refresh() 方法：加载配置文件根据注册表中的 BeanDefinition 对象封装的数据进行 bean 对象的创建public interface ApplicationContext extends BeanFactory { /** * 加载配置文件并创建对象 * * @throws Exception */ void refresh() throws Exception; }（3）AbstractApplicationContext类作为 ApplicationContext 接口的子类，该类也是非延时加载，所以在该类中定义Map集合作为 bean 对象的存储容器声明 BeanDefinitionReader 类型的变量，进行xml配置文件解析； BeanDefinitionReader 类型的对象的创建交由子类实现（因为只有子类明确创建 BeanDefinitionReader 哪个子实现类对象）public abstract class AbstractApplicationContext implements ApplicationContext { /** * 声明解析器 */ protected BeanDefinitionReader beanDefinitionReader; /** * 存储bean的容器 */ protected Map<String, Object> singleObjects = new HashMap<>(); /** * 配置文件路径 */ protected String configLocation; @Override public void refresh() throws Exception { //加载BeanDefinition beanDefinitionReader.loadBeanDefinitions(configLocation); //初始化bean this.finishBeanInitialization(); } /** * 初始化bean */ private void finishBeanInitialization() throws Exception { //获取注册表对象 BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry(); //获取BeanDefinition String[] beanNames = registry.getBeanDefinitionNames(); for (String beanName : beanNames) { //执行初始化 getBean(beanName); } } }注：finishBeanInitialization() 方法中的 getBean() 使用了模板方法（4）ClassPathXmlApplicationContext类该类主要功能是加载类路径下的配置文件，并创建 bean 对象：在构造方法中，创建 BeanDefinitionReader 对象在构造方法中，调用 refresh() 方法，用于加载配置文件、创建 bean 对象并存储到容器中重写父接口中的 getBean() 方法，并实现依赖注入public class ClassPathXmlApplicationContext extends AbstractApplicationContext { public ClassPathXmlApplicationContext(String configLocation) { this.configLocation = configLocation; //构建解析器 beanDefinitionReader = new XmlBeanDefinitionReader(); try { this.refresh(); } catch (Exception e) { } } @Override public Object getBean(String name) throws Exception { //判断对象容器中是否包含指定名称的容器对象，如果有则直接返回，反之进行创建 Object obj = singleObjects.get(name); if (obj != null) { return obj; } //获取BeanDefinition BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry(); BeanDefinition beanDefinition = registry.getBeanDefinition(name); //根据bean标签数据中的类名反射创建对象 Class<?> clazz = Class.forName(beanDefinition.getClassName()); Object beanObj = clazz.newInstance(); //执行依赖注入 for (PropertyValue propertyValue : beanDefinition.getPropertyValues()) { //name String propertyName = propertyValue.getName(); //value String value = propertyValue.getValue(); //ref String ref = propertyValue.getRef(); if (ref != null && !"".equals(ref)) { //获取依赖的bean对象 Object bean = getBean(ref); //拼接方法名 String methodName = StringUtils.getSetMethodNameByFieldName(propertyName); Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getName().equals(methodName)) { method.invoke(beanObj, bean); } } } if (value != null && !"".equals(value)) { String methodName = StringUtils.getSetMethodNameByFieldName(propertyName); Method method = clazz.getMethod(methodName, String.class); method.invoke(beanObj, value); } } //在返回之前将该对象存储到bean容器中 singleObjects.put(name, beanObj); return beanObj; } @Override public <T> T getBean(String name, Class<? extends T> clazz) throws Exception { Object bean = getBean(name); if (bean == null) { return null; } return clazz.cast(bean); } }5. 补充pom.xml <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency>项目结构：
（1）概述定义一个语言，定义它的文法表示，并定义一个解释器，根据文法规则来解释语言中的句子文法（语法）规则：用于描述语言的语法结构的形式规则# 例： expression ::= value | plus | minus # ::= 表示定义为 plus ::= expression '+' expression minus ::= expression '-' expression value ::= integer # 表达式可以是一个值，也可以是plus、minus运算， 而plus、minus又由表达式结合运算符构成，值的类型为整数抽象语法树在计算机科学中，抽象语法树（AbstractSyntaxTree，ATS）简称语法树（Syntax Tree），是源代码语法的一种抽象表示，它以树状的形式表现编程语言的语法结构，树上的每个节点都表示源代码中的一种结构。如：1 + 2 + 3 - 4（2）结构抽象表达式：定义解释器的接口，约定解释器的解释操作，主要包含解释方法 interpret()终结符表达式：抽象表达式的子类，实现文法与终结符相关的操作，文法中的每一个终结符都有与之对应的具体终结表达式非终结符表达式：抽象表达式的子类，实现文法与非终结符相关的操作，文法中的每条规则都对应一个非终结符表达式环境角色：包含各个解释器需要的数据或公共功能，用来传递被所有解释器共享的数据，后面的解释器可以从该角色获取相应的数据客户端：将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树，然后调用解释器的解释方法，同时也可以通过环境角色间接访问解释器的解释方法（3）案例以加减运算为例抽象表达式public abstract class AbstractExpression { /** * 解释（解析） * * @param context 环境变量 * @return */ public abstract int interpret(Context context); }非终结符表达式public class Minus extends AbstractExpression { //减号左边的表达式 private AbstractExpression left; //减号右边的表达式 private AbstractExpression right; public Minus(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) - right.interpret(context); } @Override public String toString() { return "(" + left.toString() + " - " + right.toString() + ")"; } } public class Plus extends AbstractExpression { //加号左边的表达式 private AbstractExpression left; //加号右边的表达式 private AbstractExpression right; public Plus(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) + right.interpret(context); } @Override public String toString() { return "(" + left.toString() + " + " + right.toString() + ")"; } }终结符表达式public class Variable extends AbstractExpression { //变量名 private String name; public Variable(String name) { this.name = name; } @Override public int interpret(Context context) { //直接返回变量值 return context.getVariable(this); } @Override public String toString() { return name; } }环境角色public class Context { private Map<Variable, Integer> map = new HashMap<>(); /** * 添加变量 * * @param var key * @param value value */ public void assign(Variable var, Integer value) { map.put(var, value); } /** * 获取变量 * * @param var key * @return */ public int getVariable(Variable var) { return map.get(var); } }Clientpublic class Client { public static void main(String[] args) { //创建环境对象 Context context = new Context(); //创建多个变量对象 Variable a = new Variable("a"); Variable b = new Variable("b"); Variable c = new Variable("c"); Variable d = new Variable("d"); //存储变量 context.assign(a, 1); context.assign(b, 2); context.assign(c, 3); context.assign(d, 4); //获取抽象语法树 a + b - c + d AbstractExpression expression = new Plus(a, new Minus(b, new Plus(c, d))); //解释（解析） System.out.println(expression.interpret(context)); } }（4）优缺点易于改变和扩展文法：由于解释器模式中使用类来表示语言的文法规则，因此可以使用继承等机制来扩展或改变文法实现文法较为容易：在抽象语法树中，每一个表达式节点类的实现方式都是类似的，且不是特别复杂增加新的解释表达式较为方便：在需要扩展时只需增加一个对应的终结符/非终结符表达式类，符合开闭原则复杂文法难以维护：在该模式中，每一条规则至少需要定义一个类，类的个数会随着文法规则的增加而增加执行效率低：该模式使用了大量的循环和递归调用，在解释较为复杂的句子时存在性能问题（变量类型重写抽象表达式的解释（解析）方法，直接获取对应 key 的值，非终结符表达式先调用其他表达式父类的解释（解析）方法，然后才到自身这边）
（1）概述备忘录模式又叫快照模式，在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态，以便需要时能将该对象恢复到之前保存的状态（2）结构发起人角色：记录当前时刻的内部状态信息，提供创建备忘录和恢复备忘录的功能，它可以访问备忘录里的所有信息备忘录角色：负责存储发起人的内部状态，在需要的时候提供这些内部状态给发起人管理者角色：对备忘录进行管理，提供保存与获取备忘录的功能，但其不能对备忘录没有读写权限备忘录有两个等效接口：窄接口：管理者对象（和其他除发起人对象之外的任何对象），看到的是窄接口，该接口只允许把备忘录对象传递给其他对象宽接口：发起人对象可以看到宽接口，该接口允许读取所有的数据，以便恢复对象之前的内部状态（3）案例以游戏存档为例：“白箱”备忘录备忘录角色对任何对象都提供宽接口（破坏了封装性）发起人角色public class GameRole { /** * 生命值 */ private int vit; /** * 攻击值 */ private int atk; /** * 防御值 */ private int def; public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } /** * 初始化内部状态 */ public void initState() { this.vit = 100; this.atk = 100; this.def = 100; } /** * 战斗 */ public void fight() { this.vit = 0; this.atk = 0; this.def = 0; } /** * 保存游戏角色状态 * * @return */ public RoleStateMemento saveState() { return new RoleStateMemento(vit, atk, def); } /** * 恢复角色状态 * * @param roleStateMemento */ public void recoverState(RoleStateMemento roleStateMemento) { this.vit = roleStateMemento.getVit(); this.atk = roleStateMemento.getAtk(); this.def = roleStateMemento.getDef(); } /** * 展示角色状态 */ public void displayState() { System.out.println("生命值：" + vit); System.out.println("攻击值：" + vit); System.out.println("防御值：" + vit); } }备忘录角色public class RoleStateMemento { /** * 生命值 */ private int vit; /** * 攻击值 */ private int atk; /** * 防御值 */ private int def; public RoleStateMemento() { } public RoleStateMemento(int vit, int atk, int def) { this.vit = vit; this.atk = atk; this.def = def; } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } }备忘录管理者public class RoleStateCaretaker { private RoleStateMemento roleStateMemento; public RoleStateMemento getRoleStateMemento() { return roleStateMemento; } public void setRoleStateMemento(RoleStateMemento roleStateMemento) { this.roleStateMemento = roleStateMemento; } }Clientpublic class Client { public static void main(String[] args) { System.out.println("====战斗前===="); GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.displayState(); //备份角色状态 RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setRoleStateMemento(gameRole.saveState()); System.out.println("====战斗后===="); gameRole.fight(); gameRole.displayState(); System.out.println("====恢复状态===="); gameRole.recoverState(roleStateCaretaker.getRoleStateMemento()); gameRole.displayState(); } }“黑箱”备忘录备忘录角色对发起人提供宽接口，对其他对象提供窄接口（即将备忘录类设置为发起人的内部类）发起人角色public class GameRole { /** * 生命值 */ private int vit; /** * 攻击值 */ private int atk; /** * 防御值 */ private int def; public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } /** * 初始化内部状态 */ public void initState() { this.vit = 100; this.atk = 100; this.def = 100; } /** * 战斗 */ public void fight() { this.vit = 0; this.atk = 0; this.def = 0; } /** * 保存游戏角色状态 * * @return */ public Memento saveState() { return new RoleStateMemento(vit, atk, def); } /** * 恢复角色状态 * * @param memento */ public void recoverState(Memento memento) { RoleStateMemento roleStateMemento = (RoleStateMemento) memento; this.vit = roleStateMemento.getVit(); this.atk = roleStateMemento.getAtk(); this.def = roleStateMemento.getDef(); } /** * 展示角色状态 */ public void displayState() { System.out.println("生命值：" + vit); System.out.println("攻击值：" + vit); System.out.println("防御值：" + vit); } private class RoleStateMemento implements Memento { /** * 生命值 */ private int vit; /** * 攻击值 */ private int atk; /** * 防御值 */ private int def; public RoleStateMemento() { } public RoleStateMemento(int vit, int atk, int def) { this.vit = vit; this.atk = atk; this.def = def; } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } } }备忘录接口（对外提供的窄接口）public interface Memento { }备忘录管理者角色public class RoleStateCaretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }Clientpublic class Client { public static void main(String[] args) { System.out.println("====战斗前===="); GameRole gameRole = new GameRole(); gameRole.initState(); gameRole.displayState(); //备份角色状态 RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setMemento(gameRole.saveState()); System.out.println("====战斗后===="); gameRole.fight(); gameRole.displayState(); System.out.println("====恢复状态===="); gameRole.recoverState(roleStateCaretaker.getMemento()); gameRole.displayState(); } }（4）优缺点提供了一种可恢复状态的机制，当用户需要事，可方便的恢复到某个历史状态实现了内部状态的封装，除发起人之外的角色对这些状态信息都没有读写权限简化了发起人类，内部状态由管理者进行管理，发起人无需关心，复合单一职责原则当需要存储的状态信息及频率过多过大时，需要消耗更多的资源（5）使用场景需要保存与恢复数据时需要提供可回滚操作时，如 ctrl + z 、数据库回滚等
（1）概述封装一些作用于某种数据结构中的各元素的操作，它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作（2）结构抽象访问者角色：定义对每一个元素访问的行为，它的参数就是可以访问的元素（它的方法个数理论上来说与元素个数相等）具体访问者角色：给出对每一个元素类访问时所产生的具体行为抽象元素角色：定义接受访问者的方法（即每一个元素都可以被访问者访问）具体元素角色：提供接受访问方法的具体实现，而这个具体的实现，通常情况下是使用访问者提供的访问该元素类的方法对象结构角色：一个具有容器性质或复合对象特性的类，它含有一组元素，且可以迭代这些元素，供访问者访问（3）案例以宠物喂食为例访问者角色：给宠物喂食的人具体访问者角色：宠物主人、其他人等抽象元素角色：动物抽象类具体元素角色：宠物狗、宠物猫结构对象角色：主人家抽象访问者角色public interface Person { /** * 喂猫 * * @param cat 猫 */ void feed(Cat cat); /** * 喂狗 * * @param dog 狗 */ void feed(Dog dog); }具体访问者public class Owner implements Person { @Override public void feed(Cat cat) { System.out.println("主人喂猫"); } @Override public void feed(Dog dog) { System.out.println("主人喂狗"); } } public class Someone implements Person { @Override public void feed(Cat cat) { System.out.println("客人喂猫"); } @Override public void feed(Dog dog) { System.out.println("客人喂狗"); } }抽象元素角色public interface Animal { /** * 接受访问者访问 * * @param person 访问者 */ void accept(Person person); }具体元素角色public class Dog implements Animal { @Override public void accept(Person person) { person.feed(this); System.out.println("喂狗吃狗粮"); } } public class Cat implements Animal { @Override public void accept(Person person) { person.feed(this); System.out.println("喂猫吃猫粮"); } }结构对象角色public class Home { private List<Animal> nodeList = new ArrayList<>(); void add(Animal animal) { nodeList.add(animal); } void action(Person person) { //访问者访问每一个元素 for (Animal animal : nodeList) { animal.accept(person); } } }Clientpublic class Client { public static void main(String[] args) { //创建Home Home home = new Home(); //添加元素 home.add(new Dog()); home.add(new Cat()); //创建主人对象 Owner owner = new Owner(); //主人喂宠物 home.action(owner); } }（4）优缺点扩展性好：在不修改对象结构中的元素的情况下，为对象结构中的元素添加新的功能复用性好：通过访问者来定义整个对象结构的通用的功能，从而提高代码复用分离无关行为：通过访问者来分离无关的行为，把相关的行为封装在一起，构成一个访问者，使得每一个访问者的功能都比较单一对象结构变化困难：每增加一个新的元素类，都要在每一个具体访问者中增加相应的具体操作，违背了开闭原则违反了依赖倒置原则：访问者依赖具体类，而不依赖抽象类（5）使用场景对象结构稳定，但其操作算法经常变更时对象结构中对象需要提供多种不同且不相关的操作，而且要避免让这些操作的变化影响对象的结构时（6）扩展访问者模式使用了双分派技术1. 分派变量被声明时的类型叫做变量的静态类型，变量所引用的对象的真实类型叫实际类型 Map map = new HashMap()静态分派：发生在编译时期，分派根据静态类型信息发生，如：方法重载动态分派：发生在运行时期，动态分派动态地置换掉某个方法，如：方法重写2. 动态分派public class Animal { public void execute() { System.out.println("Animal"); } } public class Dog extends Animal { @Override public void execute() { System.out.println("Dog"); } } public class Cat extends Animal { @Override public void execute() { System.out.println("Cat"); } } public class Client { public static void main(String[] args) { Animal a = new Dog(); a.execute(); Animal a1 = new Cat(); a1.execute(); } }Java编译器在编译时期并不总是知道哪些代码会被执行，因为编译器仅仅知道对象的静态类型，而方法的调用则是根据对象的真实类型3. 静态分派public class Animal { } public class Dog extends Animal { } public class Cat extends Animal { } public class Execute() { public void print(Animal a) { System.out.println("Animal"); } public void print(Dog d) { System.out.println("Dog"); } public void print(Cat c) { System.out.println("Cat"); } } public class Client { public static void main(String[] args) { Animal a = new Animal(); Animal d = new Dog(); Animal c = new Cat(); Execute execute = new Execute(); execute.print(a); //Animal execute.print(d); //Animal execute.print(c); //Animal } }重载是根据方法的静态类型进行的，该分派过程在编译期完成，所以打印结果都是 Animal4. 双分派双分派在选择一个方法的时候，不仅要根据消息接收者的运行时区别，还要根据参数的运行时区别public class Animal { public void accept(Execute execute) { execute.print(this); } } public class Dog extends Animal { @Override public void accept(Execute execute) { execute.print(this); } } public class Cat extends Animal { @Override public void accept(Execute execute) { execute.print(this); } } public class Execute() { public void print(Animal a) { System.out.println("Animal"); } public void print(Dog d) { System.out.println("Dog"); } public void print(Cat c) { System.out.println("Cat"); } } public class Client { public static void main(String[] args) { Animal a = new Animal(); Animal d = new Dog(); Animal c = new Cat(); Execute execute = new Execute(); a.accept(execute); //Animal d.accept(execute); //Dog c.accept(execute); //Cat } }客户端将 Execute 作为参数传递给 Animal 类型的变量调用的方法，这里通过方法重写完成了第一次分派（动态分派），同时也将自己 this 作为参数传递到 Execute.print() 方法中，这里通过方法重载完成了第二次分派（静态分派）双分派实现动态绑定的本质就是在重载委派之前加上继承体系中的重写
（1）概述提供一个对象来顺序访问聚合对象中的一系列数据，而不暴露内部对象的表示（2）结构抽象聚合角色：定义存储、添加、删除聚合元素以及创建迭代器对象的接口具体聚合角色：实现抽象聚合类，返回一个具体迭代器的实例抽象迭代器角色：定义访问和遍历聚合元素的接口，通常包含 hasNext()、next() 等方法具体迭代器角色：实现抽象迭代器接口中所定义的方法，完成对聚合对象的遍历，记录遍历的当前位置（3）案例以遍历学生对象集合为例抽象聚合角色public interface StudentAggregate { /** * 添加元素 * * @param student */ void add(Student student); /** * 移除元素 * * @param student */ void remove(Student student); /** * 获取迭代器 * * @return */ StudentIterator getStudentIterator(); }具体聚合角色public class StudentAggregateImpl implements StudentAggregate { private List<Student> list = new ArrayList<>(); @Override public void add(Student student) { list.add(student); } @Override public void remove(Student student) { list.remove(student); } @Override public StudentIterator getStudentIterator() { return new StudentIteratorImpl(list); } }抽象迭代器角色public interface StudentIterator { /** * 判断是否还有元素 * * @return */ boolean hasNext(); /** * 获取下一个元素 * * @return */ Student next(); }具体迭代器角色public class StudentIteratorImpl implements StudentIterator { private List<Student> list; //记录遍历时的位置 private int position = 0; public StudentIteratorImpl(List<Student> list) { this.list = list; } @Override public boolean hasNext() { return position < list.size(); } @Override public Student next() { Student currentStudent = list.get(position); position++; return currentStudent; } }Clientpublic class Client { public static void main(String[] args) { //创建聚合对象 StudentAggregateImpl studentAggregate = new StudentAggregateImpl(); //添加元素 studentAggregate.add(new Student("孙笑川", "001")); studentAggregate.add(new Student("药水哥", "002")); studentAggregate.add(new Student("刘波", "003")); //获取迭代器对象 StudentIterator iterator = studentAggregate.getStudentIterator(); //遍历 while (iterator.hasNext()) { System.out.println(iterator.next()); } } }（4）优缺点支持以不同的方式遍历一个聚合对象，在同一个聚合对象上可以定义多种遍历方式，在迭代器模式中只需要用一个不同的迭代器来替换原有的迭代器即可改变遍历算法简化了聚合类，在原有的聚合类中不需要再自行提供遍历等方法由于引入了抽象层，新增新的聚合类和迭代器类都很方便，满足开闭原则（5）使用场景当需要为聚合对象提供多种遍历方式时当需要为遍历不同的聚合结构提供一个统一的接口时当需要访问一个聚合对象的内容而无需暴露其内部细节时
（1）概述中介者模式又称调停模式，定义一个中介者角色来封装一系列对象之间的交互，使原有对象之间的耦合松散，且可以独立的改变它们之间的交互（2）结构抽象中介者：它是中介者的接口，提供了同事对象注册与转发同事对象信息的抽象方法具体中介者：实现中介者接口，定义一个 List 来管理同事对象，协调各个同事对象之间的交互关系，须依赖于同事对象抽象同事类：定义同事类的接口，保存中介者对象，提供同事对象交互的抽象方法，实现所有相互影响的同事类的公共功能具体同事类：实现抽象同事类接口，当需要与其他同事对象交互时，由中介者对象负责后续的交互（3）案例以租房为例抽象中介者public abstract class Mediator { /** * 交流 * * @param message 信息 * @param person 抽象同事类 */ public abstract void contact(String message, Person person); }具体中介者public class MediatorStructure extends Mediator { //聚合房东、租房者 private HouseOwner houseOwner; private Tenant tenant; public HouseOwner getHouseOwner() { return houseOwner; } public void setHouseOwner(HouseOwner houseOwner) { this.houseOwner = houseOwner; } public Tenant getTenant() { return tenant; } public void setTenant(Tenant tenant) { this.tenant = tenant; } @Override public void contact(String message, Person person) { if (person == houseOwner) { tenant.getMessage(message); } else { houseOwner.getMessage(message); } } }抽象同事类public abstract class Person { protected String name; protected Mediator mediator; public Person(String name, Mediator mediator) { this.name = name; this.mediator = mediator; } }具体同事类public class HouseOwner extends Person { public HouseOwner(String name, Mediator mediator) { super(name, mediator); } /** * 与中介沟通 * * @param message 信息 */ public void contact(String message) { mediator.contact(message, this); } /** * 获取信息 * * @param message 信息 */ public void getMessage(String message) { System.out.println("房东获取到的信息：" + message); } } public class Tenant extends Person { public Tenant(String name, Mediator mediator) { super(name, mediator); } /** * 与中介沟通 * * @param message 信息 */ public void contact(String message) { mediator.contact(message, this); } /** * 获取信息 * * @param message 信息 */ public void getMessage(String message) { System.out.println("租房者获取到的信息：" + message); } }Clientpublic class Client { public static void main(String[] args) { //创建中介者 MediatorStructure mediatorStructure = new MediatorStructure(); //租房者 Tenant tenant = new Tenant("孙笑川", mediatorStructure); //房东 HouseOwner houseOwner = new HouseOwner("刘波", mediatorStructure); //中介需知道具体的租房者和房东 mediatorStructure.setTenant(tenant); mediatorStructure.setHouseOwner(houseOwner); tenant.contact("我要租房"); houseOwner.contact("我这里有"); } }（4）优缺点松散耦合：通过把多个同事对象之间的交互封装到中介者对象里面，从而使得同事对象之间松散耦合，可以做到互补依赖，同事对象也可以独立的变化和复用集中控制交互：多个同事对象的交互，被封装在中介者对象中集中管理，在交互发生变化的时候，只需修改中介者（或者进行扩展）一对多的关联转变为一对一：引入中介者之后，中介者与同事对象的关系变为双向一对一，使同事对象的关系易于理解和实现当同事类较多时，中介者的职责很重，结构复杂且难以维护（5）使用场景系统中对象间存在复杂的引用关系，系统结构混乱且难以理解需创建一个运行于多个类之间的对象，又不想生成新的子类时
（1）概述观察者模式又称发布 - 订阅模式，它定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象，这个主题对象在状态变化时，会通知所有的观察者对象，使它们能够自动更新自己（2）结构抽象主题（抽象被观察者）：抽象主题角色把所有观察者对象保存在一个集合里，每个主题都可以有任意数量的观察者，抽象主题提供一个接口，可以增加/删除观察者对象具体主题（具体被观察者）：该角色将有关状态存入具体观察者对象，在具体主题的内部发生改变时，给所有注册过的观察者发送通知抽象观察者：它定义了一个更新接口，使得在得到主题更改时通知更新自己具体观察者：实现抽象观察者定义的更新接口，以便在得到主题更改时通知更新自身的状态（3）案例以订阅公众号为例抽象主题角色public interface Subject { /** * 添加观察者对象（订阅者） * @param observer 观察者对象 */ void attach(Observer observer); /** * 删除观察者对象（订阅者） * @param observer 观察者对象 */ void detach(Observer observer); /** * 通志观察者（订阅者）更新消息 * @param message 消息 */ void notify(String message); }具体主题角色public class SubscriptionSubject implements Subject { private List<Observer> userList = new ArrayList<>(); @Override public void attach(Observer observer) { userList.add(observer); } @Override public void detach(Observer observer) { userList.remove(observer); } @Override public void notify(String message) { //通知所有订阅者 for (Observer observer : userList) { observer.update(message); } } }抽象观察者角色public interface Observer { /** * 更新 * @param message 消息 */ void update(String message); }具体观察者角色public class User implements Observer { private String name; public User(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + "接收到消息：" + message); } }Clientpublic class Client { public static void main(String[] args) { //创建公众号 SubscriptionSubject subject = new SubscriptionSubject(); //订阅公众号 subject.attach(new User("孙笑川")); subject.attach(new User("药水哥")); subject.attach(new User("刘波")); //公众号发布新的消息 subject.notify("带带大师兄"); } }（4）优缺点降低了被观察者与观察者之间的耦合被观察者发送消息，所有观察者都可以收到，可以实现广播机制观察者过多时，对系统性能会产生一定的影响如果被观察者有循环依赖，在发送消息时可能导致观察者循环调用（5）使用场景当对象存在一对多关系，一个对象的状态发生改变会影响其他的对象当一个抽象模型存在两个方面，其中一方面依赖于另一方面时
（1）概述对有状态的对象，把复杂的“判断逻辑“提取到不同的状态对象中，允许其状态对象在其内部状态发生改变时改变其行为（2）结构环境角色：也称为上下文，它定义了客户程序需要的接口，维护一个当前状态并将与状态相关的操作委托给当前状态对象来处理抽象状态角色：定义接口用以封装环境对象中的特定状态所对应的行为具体状态角色：实现抽象状态所定义的行为（3）案例以乘坐电梯为例环境角色public class Context { /** * 对应状态对象的常量 */ public final static OpeningState OPENING_STATE = new OpeningState(); public final static ClosingState CLOSING_STATE = new ClosingState(); public final static RunningState RUNNING_STATE = new RunningState(); public final static StoppingState STOPPING_STATE = new StoppingState(); /** * 当前电梯状态变量 */ private LiftState liftState; public LiftState getLiftState() { return liftState; } public void setLiftState(LiftState liftState) { this.liftState = liftState; //设置当前状态对象中的Context对象 liftState.setContext(this); } public void open() { this.liftState.open(); } public void close() { this.liftState.close(); } public void run() { this.liftState.run(); } public void stop() { this.liftState.stop(); } }抽象状态角色public abstract class LiftState { //环境角色类变量 protected Context context; public void setContext(Context context) { this.context = context; } /** * 开门 */ public abstract void open(); /** * 关门 */ public abstract void close(); /** * 运行 */ public abstract void run(); /** * 停止 */ public abstract void stop(); }具体状态角色public class OpeningState extends LiftState { @Override public void open() { System.out.println("电梯门开了"); } @Override public void close() { //修改状态 super.context.setLiftState(Context.CLOSING_STATE); //调用当前状态中的Context中的close方法 super.context.close(); } @Override public void run() { } @Override public void stop() { } } public class RunningState extends LiftState { @Override public void open() { } @Override public void close() { } @Override public void run() { System.out.println("电梯正在运行"); } @Override public void stop() { super.context.setLiftState(Context.STOPPING_STATE); super.context.stop(); } } public class ClosingState extends LiftState { @Override public void open() { super.context.setLiftState(Context.OPENING_STATE); super.context.open(); } @Override public void close() { System.out.println("电梯门关了"); } @Override public void run() { super.context.setLiftState(Context.RUNNING_STATE); super.context.run(); } @Override public void stop() { super.context.setLiftState(Context.STOPPING_STATE); super.context.stop(); } } public class StoppingState extends LiftState { @Override public void open() { super.context.setLiftState(Context.OPENING_STATE); super.context.open(); } @Override public void close() { super.context.setLiftState(Context.CLOSING_STATE); super.context.close(); } @Override public void run() { super.context.setLiftState(Context.RUNNING_STATE); super.context.run(); } @Override public void stop() { System.out.println("电梯停了"); } }Clientpublic class Client { public static void main(String[] args) { //创建环境角色对象 Context context = new Context(); //设置当前电梯状态 context.setLiftState(new RunningState()); context.open(); context.close(); context.run(); context.stop(); } }（4）优缺点将所有与某个状态相关的行为放到一个类中，并且可以方便地增加新的状态，只需要改变对象状态即可改变对象的行为允许状态转换逻辑与状态对象合成一体，而不是某一个巨大的条件语句块可能导致类和对象的个数增多结果与实现较为复杂，若果使用不当可能会导致结构与代码的混乱不符合开闭原则（5）使用场景当一个对象的行为取决于它的状态，并且它必须在运行时根据状态改变他的行为时一个操作中含有庞大的分支结构，并且这些分支决定于对象的状态时
（1）概述为了避免请求发送者与多个请求处理者耦合在一起，将所有请求的处理者通过前一对象记住其下一个对象的引用而连城一条链；当有请求发生时，可将请求沿着这条链传递，只到有对象处理它为止（2）结构抽象处理者角色：定义处理请求的接口，包含抽象处理方法和一个后继链接具体处理者角色：实现抽象处理者的处理方法，判断能否处理本次请求，如果可以处理则处理，否则将该请求转发给后继者客户类角色：创建处理链，并向链头的具体处理者对象提交请求，它不关心处理细节及请求传递的过程（3）案例以请假为例抽象处理者角色public abstract class Handler { protected final static int ONE = 1; protected final static int THREE = 3; protected final static int SEVEN = 7; //不同角色可以处理的请假天数区间 private int startNum; private int endNum; //声明后继者（该案例中的上级领导） private Handler nextHandler; public Handler(int startNum) { this.startNum = startNum; } public Handler(int startNum, int endNum) { this.startNum = startNum; this.endNum = endNum; } /** * 设置上级领导对象 * * @param nextHandler */ public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; } /** * 各级领导处理请假条的方法 * * @param leave */ protected abstract void handlerLeave(LeaveRequest leave); /** * 提交请假申请 * * @param leave */ public final void submit(LeaveRequest leave) { //当前领导审批 this.handlerLeave(leave); //上级领导审批 if (this.nextHandler != null && leave.getNum() > this.endNum) { this.nextHandler.handlerLeave(leave); } else { System.out.println("流程结束"); } } }具体处理者角色public class GroupLeader extends Handler { public GroupLeader() { super(0, Handler.ONE); } @Override protected void handlerLeave(LeaveRequest leave) { System.out.println(leave.getName() + "由于" + leave.getContent() + "，请假：" + leave.getNum() + "天"); System.out.println("组长审批意见：同意"); } } public class Manager extends Handler { public Manager() { super(Handler.ONE, Handler.THREE); } @Override protected void handlerLeave(LeaveRequest leave) { System.out.println(leave.getName() + "由于" + leave.getContent() + "，请假：" + leave.getNum() + "天"); System.out.println("部门经理意见：同意"); } } public class GeneralManager extends Handler { public GeneralManager() { super(Handler.THREE, Handler.SEVEN); } @Override protected void handlerLeave(LeaveRequest leave) { System.out.println(leave.getName() + "由于" + leave.getContent() + "，请假：" + leave.getNum() + "天"); System.out.println("总经理审批意见：同意"); } }客户类角色public class LeaveRequest { //请假人 private String name; //请假天数 private int num; //请假事由 private String content; public LeaveRequest(String name, int num, String content) { this.name = name; this.num = num; this.content = content; } public String getName() { return name; } public int getNum() { return num; } public String getContent() { return content; } }Clientpublic class Client { public static void main(String[] args) { //创建请假条 LeaveRequest leaveRequest = new LeaveRequest("孙笑川", 2, "感冒"); //各级领导对象 GroupLeader groupLeader = new GroupLeader(); Manager manager = new Manager(); GeneralManager generalManager = new GeneralManager(); //设置处理者链 groupLeader.setNextHandler(manager); manager.setNextHandler(generalManager); //发起请假申请 groupLeader.submit(leaveRequest); } }（4）优缺点降低了请求发送者和接收者的耦合度可根据需求添加新的处理类，复合开闭原则增强了给对象指派职责的灵活性，当工作流程发生变化时，可以动态的改变链内的成员或成员之间的顺序，也可以动态的新增/删除责任简化了对象之间的连接，一个对象只需保持一个指向其后继者的引用，不需要保持其他所有处理者的引用，对客户端来说避免了众多的 if...else 语句职责明确，每个类只需关心自己的职责内容，不能处理的传递给下一个对象，复合类的单一职责原则不能保证每一个请求一定被处理，由于一个请求没有明确的接收者，所以不能暴政它一定被处理，该请求可能一直传递到链的末端也得不到处理较长的责任链可能涉及的多个处理对象，对性能有一定的影响责任链建立的合理性需要靠客户端来保证，增加了客户端的复杂性，可能会由于责任链的设置错误而导致系统出错（如循环调用等）
（1）概述将一个请求封装为一个对象，使发出请求的责任和执行请求的责任分割开，使两者之间通过命令对象来进行沟通，便于命令对象的存储、传递、调用、增加及管理（2）结构抽象命令角色：定义命令的接口，声明执行的方法具体命令角色：具体的命令，实现命令接口，持有接收者，并调用接收者的功能来完成命令要执行的操作实现者/接收者角色：执行命令的对象（任何类都可能成为一个接收者，只要它能够实现命令要求实现的相应功能）调用者/请求者角色：要求命令对象执行请求，持有命令对象（一个或多个），客户端真正触发命令并要求命令执行相应操作的地方（即使用命令对象的入口）（3）案例以点餐为例抽象命令角色public interface Command { /** * 执行命令 */ void execute(); }public class Order { private int diningTable; private Map<String, Integer> foodDic = new HashMap<>(); public int getDiningTable() { return diningTable; } public void setDiningTable(int diningTable) { this.diningTable = diningTable; } public Map<String, Integer> getFoodDic() { return foodDic; } public void setFood(String foodName, int num) { foodDic.put(foodName, num); } }具体命令角色public class OrderCommand implements Command { //持有接收者对象 private SeniorChef receiver; //持有订单对象 private Order order; public OrderCommand(SeniorChef receiver, Order order) { this.receiver = receiver; this.order = order; } @Override public void execute() { System.out.println(order.getDiningTable() + "号桌的订单："); Map<String, Integer> foodDic = order.getFoodDic(); for (String foodName : foodDic.keySet()) { receiver.makeFood(foodName, foodDic.get(foodName)); } System.out.println(order.getDiningTable() + "号桌的菜品已准备完毕！"); } }实现者/接收者角色public class SeniorChef { public void makeFood(String foodName, int num) { System.out.println("制作了" + num + "份 " + foodName); } }调用者/请求者角色public class Waiter { //持有多个命令对象 private List<Command> commands = new ArrayList<>(); public void command(Command command) { commands.add(command); } public void orderUp() { System.out.println("新订单来了"); for (Command command : commands) { if (command != null) { command.execute(); } } } }Clientpublic class Client { public static void main(String[] args) { //创建订单 Order order1 = new Order(); order1.setDiningTable(1); order1.setFood("小混沌", 1); order1.setFood("煎饼", 1); Order order2 = new Order(); order2.setDiningTable(2); order2.setFood("小炒肉盖饭", 1); order2.setFood("酸梅汤", 1); //创建厨师 SeniorChef receiver = new SeniorChef(); //创建命令对象 OrderCommand command1 = new OrderCommand(receiver, order1); OrderCommand command2 = new OrderCommand(receiver, order2); //创建服务员（调用者） Waiter waiter = new Waiter(); waiter.command(command1); waiter.command(command2); //发起命令 waiter.orderUp(); } }（4）优缺点将调用操作的对象与实现该操作的对象解耦，降低了系统的耦合度增加/删除命令时不会影响其他的类，符合开闭原则通过与组合模式结合，将多个命令装配成一组命令，可以实现宏命令可以实现命令的撤销 redo 与恢复 undo使用该模式可能产生很多的具体命令类（但不会造成类爆炸）系统结构更加复杂（5）使用场景系统需要将请求调用者和接收者解耦，使两者不进行直接交互时系统需要根据不同的情况指定请求、排队请求、执行请求时系统需要支持命令的撤销 redo 与恢复 undo 时