github地址: 点击这里
原型模式类图
Prototype:原型类,声名一个克隆自己的接口。
ConcretePrototype: 具体原型类,实现一个克隆自己的操作。
Client:让一个原型对象克隆自己,从而创建一个新的对象(属性一样)。
应用在spring的bean中。
以房子案例,分为以下几个部分
建造者模式分为,产品、抽象建造者、实际建造者(实现)、指挥者。
抽象工厂与建造者模式区别
类适配器
举例为手机需要充电器进行充电。
电源220 充电器(适配器将电压调为5V) 手机(要有充电功能)
对象适配器
接口适配器
AbsAdapter 空实现接口,然后A调用后,可以用匿名内部类进行覆盖空实现方法。从而调用某个类。
注:
Springmvc中在请求中就是用的适配器
实现请求类图为
通过请求来找到 Controller 然后HandlerAdapter 找到对应的适配器,通过对应的适配器,在执行相应的Controller方法。
最早需求为对手机进行分类整理。但是这种方式,会使得改什么都要相互关联
桥接模式
品牌为接口,实现类为不同品牌(没给我品牌有对应的功能)
定义手机 吧品牌属性接过,通过品牌 掉方法。
定义不同样式,继承手机,通过父类调用接口方法。
桥接模式思路为:把抽象的类(通过调用被人的方法)与实现(实际干活的)的分开
应用在JDBC连接为桥接模式
案例为:点各类咖啡+奶/巧克力/豆浆,会有不同的价位。需要满足可扩展性等。
问题:选择的种类是在太多,如果按辛巴克的规模那将是无限多的。
引用到装饰者模式——动态的讲功能附加到对象上。
通过下图可以看出 被装饰者,是被包括在装饰者中。通过递归的方式,将被包裹的新对象又变为被装饰者。
个人思路:一个祖父类。被两个儿子继承,其中一个子类,需要接受另外一个子类的对象,
传递的是需要被装饰的类。多态的妙用。
案例:为想展示出某个学校的目录层级,院,系。
如果不懂设计模式会想到继承关系,但是那是效率最低的。因此,可以用到部分整体模式,即——组合模式。
类图如下
注:聚合的是 由Organization类 分别聚合到College、University
这里如此画是因为方便体现
个人理解,因为学校、院、等功能与属性差不多、因此可以定义一个管理的抽象类,非叶子结点继承,并复写其方法,并且都聚合这个管理类。
叶子结点也要继承,但是不用复写方法。
案例 :家庭电影,你需要,
非常的麻烦,你需要把所有的机器开关给点开。
传统解决方案。
可以看出是非常的不方便。
以下为外观模式设计图。
就是把各个子系统单例起来,然后在外观类聚合子系统,并将每个子系统的单例,分类(创建新的方法)调用。最后在客户端上直接调用外观类的方法。
该模式应用在MyBatis框架中的Configuration去创建MetaObject 。
该模式类图如下。
private HashMap<String,ConcreteWebSite> pool =new HashMap<>();
public Website getweb(String Type){
if(!pool.containsKey(Type)){
pool.put(Type,new ConcreteWebSite(Type));
}
return (Website) pool.get(Type);
}
可以看出享字的精髓在于 通过Hashmap 来控制,对不同的key会创造出新的value类对象,因此key相同时 ,是不会创造出新的对象的。
静态代理
案例为,老师生病,代课老师来上课。类图如下
动态代理
类图如下
动态代理的核心为反射
核心代码如下
public Object getProxyInstance(){
//参数说明
//1. ClassLoader loader :指定当前目标对象使用的类加载器,获取加载器的方法固定。
//2.Class>[] interfaces: 目标对象实现的接口类型,使用泛型方法确定类型
//3.InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器方法,会把当前执行的目标对象方法作为参数传入。
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始");
//反射机制,调用目标对象
Object returnval=method.invoke(target,args); //参数有则继续写
System.out.println("JDK代理提交");
return returnval;
}
});
}
cglib代理
该代理在Spring 拦截机制中为主流使用。
注意事项。
类图如下
和动态代理差不多,1.只是用cglib进行(获取一个)get方法获取被代理类的class文件。
2.然后通过重写intecept进行对获取到的代理类进行具体操作。
类图与解析如下
个人理解:就是在抽象类的方法中设置一个模板方法。(fina)不能被重写
模板方法(make)包括,(制作豆浆的步骤。)
然后通过通过创建子类的对象,返回值为父类的。调用make方法。
总结
在抽象方法中,有个方法负责调用,各个子类可以通过复写进行不同的操作(用多态)进行模板中的方法进行不同的书写。
钩子方法
可以定义一个布尔方法,通过子类复写,决定某个方法执行与否。
应用
Sping IOC 容器初始化时,用到了模板模式。
public class RemoteController {
//各操作命令集合
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteController(){
onCommands = new Command[5];
offCommands = new Command[5];
for(int i=0;i<5;i++){
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
public void setCommands(int o,Command oncommand,Command offCommand)
{
onCommands[o]=oncommand;
offCommands[o]=offCommand;
}
public void onButtonWasPushed(int o){
onCommands[o].execete();
//记录一下 用于撤销
undoCommand=onCommands[o];
}
public void offButtonWasPushed(int o){
offCommands[o].execete();
//记录一下 用于撤销
undoCommand=offCommands[o];
}
public void undoButtonWasPushed(int o){
undoCommand.undo();
}
}
总结:遥控器精髓就是定义一个接口(父)对象数组,通过编号进行存储对象(即子类/实现类对象),如果新增对象,我们只需要通过遥控器对象,调用set方法绑定对象即可。减小了代码耦合度。
案例应用
案例类图
总结:访问者模式为双分派,把人的分类,与行为的分类进行解耦。如果继续添加行为,也只需继续实现Action即可,无需改动。
与策略模式相同,都是符合开闭原则。
案例为:展示学校的树形结构。
案例类图
总结:把数据添加与迭代进行分离。实现Iterator接口,把类变成迭代器类型的类。
案例为气象站为各个接入方提供数据,各个接入方为观察者。
案例类图:
总结:这是典型的一对多的问题,需要聚合多的一方的父类(实现类),这样大大的便于扩展。
案例为游戏角色恢复。
总结就是:多创建一个Caretaker 用来备份当前的属性,(把当前对象传给备用类的引用)上图Memento 为备份属性类。
案例用解释器模式完成四则运算。
案例类图
这个模式的主要逻辑为,在创建不同的Calculator时,而创建不同的Expression子类对象。并通过HashMap 解析不同的Expression对象对应的值。然后通过堆栈: 堆栈介绍.进行管理被分解的式子元素
核心代码如下
package sun.Interpreter;
import java.util.HashMap;
import java.util.Stack;
public class Calculator
{
//定义表达式
private Expression expression;
public Calculator(String exptre){
Stack<Expression> stack=new Stack<>();
//将表达式拆分成字符数组
char[] charArray=exptre.toCharArray();
Expression left=null;
Expression right = null;
//遍历char字符数组。
//并对不同情况,做相应处理
for(int i=0;i<charArray.length;i++)
{
switch (charArray[i]){
case '+':
left = stack.pop(); //如果是+号 就先取出左表达式。
//因为符号附近为数字,因此创建Var类型的Expression
right = new VarExpression(String.valueOf(charArray[++i]));//然后取出右表达式。
stack.push(new AddExpression(left,right));
break;
case '-':
left=stack.pop();
right=new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left,right));
break;
default:
//如果是个Var 那么就继续往栈里放
stack.push(new VarExpression(String.valueOf(i)));
break;
}
}
this.expression=stack.pop();
}
public int run(HashMap<String,Integer>var){
return this.expression.interpreter(var);
}
}
状态模式案例:
案例类图:
总结:由于状态发生变化,会有不同的行为,因此把状态作为接口进行实现。活动类中要聚合所有的状态子类,所有的状态子类中也包含活动类。不同状态子类,通过调用Activity类设置该状态的行为。
案例为鸭子,不同颜色的鸭子有不同的行为。
案例类图:
总结:策略模式为开闭原则的典型。我们可以把鸭子的每个行为,定为接口。因为每个行为比如飞翔,会有飞的高矮低等不同行为。只需要通过不同的接口,设置每个鸭子的不同行为即可。
案例需求:
案例类图:
总结:把请求与处理分开。最主要是 Approver 聚合自己后,可以通过设置子类实例调用,从而完成一串行为链。 设置行为链代码如下。
注意的是 我们需要设置结点数量,我们需要控制结点数量。
package ResponsibilityChain;
public class Client {
public static void main(String[] args) {
//创建请求
PurchaseRequest purchaseRequest=new PurchaseRequest(1,50000,0155464);
//创建角色
DepartmentApprover departmentApprover=new DepartmentApprover("张主任");
CollegeApprover collegeApprover=new CollegeApprover("李院士");
ViceSchool viceSchool=new ViceSchool("陈副校长");
SchoolMastApprover schoolMastApprover=new SchoolMastApprover("孙校长");
//设置处理顺序(处理人应该构成一个环形)//这样有些低的请求校长也能处理
departmentApprover.setApprover(collegeApprover);
collegeApprover.setApprover(viceSchool);
viceSchool.setApprover(schoolMastApprover);
schoolMastApprover.setApprover(departmentApprover);
//请求调用,从主任处理
departmentApprover.processRequest(purchaseRequest);
}
}
完结: