设计模式
设计模式是一种抽象的编程思想,它不会局限于某一种编程语言,也就是说在任何面向对象的编程语言中都有它的应用场景,在面向过程,函数式编程提起设计模式是没有任何意义的。
设计模式中的六大原则:单一职责原则,里氏替换原则,依赖倒置原则,接口隔离原则,迪米特法则,开闭原则。
总体来说设计模式可以分为三大类:
创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
行为型模式(11种):策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。
创建型模式
后续补发。。。。
结构型模式
代理模式Proxy:
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。为其他对象提供一种代理以控制对这个对象的访问。
代理模式Proxy:
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。为其他对象提供一种代理以控制对这个对象的访问。
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。为其他对象提供一种代理以控制对这个对象的访问。
Jdk动态代理实现:
在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行。
InvocationHandler:接口是给动态代理类实现的,负责处理被代理对象的操作的。
Proxy:是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。
接下来我们看下实例,动老师在线开车动态指定代理时间是如何实现的:
package com.zking.hujianze.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;
interface ITeacherDao {
String teach();
ITeacherDao sleep(int minutes);
}
class TeacherDao implements ITeacherDao{
@Override
public String teach() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date())+":老师在线开车";
}
@Override
public ITeacherDao sleep(int minutes) {
System.out.println("老师开了" + minutes + "分钟");
return this;
}
}
//真实代理类的外衣
class TeacherDaoProxy{
private ITeacherDao target;
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
public Object xxx(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
String methodName = method.getName();
System.out.println("目标方法" + methodName + ":jdk代理开始...");
System.out.println("真实代理对象:"+proxy.getClass());
System.out.println("目标对象:"+target.getClass());
if("sleep".equals(methodName)){
//method.invoke(target, args);
//obj = proxy;
obj = method.invoke(target, args);
}else {
//proxy是真实代理类,method是目标方法,args是目标方法携带的参数
obj = method.invoke(target, args);
}
System.out.println("目标方法" + methodName + ":jdk代理结束...");
return obj;
}
});
}
}
public class Client {
public static void main(String[] args) {
TeacherDaoProxy proxy = new TeacherDaoProxy(new TeacherDao());
ITeacherDao ins = (ITeacherDao) proxy.xxx();
System.out.println("===========代理类实例被使用 begin=============");
System.out.println(ins);
System.out.println("===========代理类实例被使用 end=============");
System.out.println(ins.teach());
//System.out.println(proxy.execute());
System.out.println("===========代理类实例被使用 begin=============");
ins.sleep(10);
System.out.println("===========代理类实例被使用 end=============");
ins.sleep(20).sleep(60);
}
}
以下输出为:
===========代理类实例被使用 begin============= 目标方法toString:jdk代理开始... 真实代理对象:class com.zking.hujianze.proxy.$Proxy0 目标对象:class com.zking.hujianze.proxy.TeacherDao 目标方法toString:jdk代理结束... com.zking.hujianze.proxy.TeacherDao@12a3a380 ===========代理类实例被使用 end============= 目标方法teach:jdk代理开始... 真实代理对象:class com.zking.hujianze.proxy.$Proxy0 目标对象:class com.zking.hujianze.proxy.TeacherDao 目标方法teach:jdk代理结束... 2022-04-20:老师在线开车 ===========代理类实例被使用 begin============= 目标方法sleep:jdk代理开始... 真实代理对象:class com.zking.hujianze.proxy.$Proxy0 目标对象:class com.zking.hujianze.proxy.TeacherDao 老师开了10分钟 目标方法sleep:jdk代理结束... ===========代理类实例被使用 end============= 目标方法sleep:jdk代理开始... 真实代理对象:class com.zking.hujianze.proxy.$Proxy0 目标对象:class com.zking.hujianze.proxy.TeacherDao 老师开了20分钟 目标方法sleep:jdk代理结束... 老师开了60分钟
cgLib的动态代理实现 :
package com.zking.hujianze.proxy.demo2;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//import java.lang.reflect.InvocationHandler;//Cglib代理不被引用
import java.lang.reflect.Method;
//import java.lang.reflect.Proxy;//Cglib代理不被引用
import java.text.SimpleDateFormat;
import java.util.Date;
class TeacherDao {
public String teach() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date()) + ":老师在线开车";
}
public TeacherDao sleep(int minutes) {
System.out.println("老师开了" + minutes + "分钟");
return this;
}
}
//真实代理类的外衣
class TeacherDaoProxy implements MethodInterceptor {
private Object target;
public TeacherDaoProxy(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object proxyIns, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
Object res;
System.out.println("目标方法" + methodName + ":cglib代理开始...");
System.out.println("真实代理对象:" + proxyIns.getClass());
System.out.println("目标对象:" + target.getClass());
if ("sleep".equals(methodName)) {
//method.invoke(target, args);
//obj = proxy;
res = method.invoke(target, args);
//res = methodProxy.invokeSuper(proxyIns,args);
res = proxyIns;
} else {
//proxy是真实代理类,method是目标方法,args是目标方法携带的参数
res = method.invoke(target, args);
}
System.out.println("目标方法" + methodName + ":cglib代理结束...");
return res;
}
}
public class Client {
public static void main(String[] args) {
TeacherDao proxy = (TeacherDao) new TeacherDaoProxy(new TeacherDao()).getProxyInstance();
proxy.sleep(111).sleep(222);
}
}
以下输出为:
目标方法sleep:cglib代理开始... 真实代理对象:class com.zking.hujianze.proxy.demo2.TeacherDao$$EnhancerByCGLIB$$ebe7c940 目标对象:class com.zking.hujianze.proxy.demo2.TeacherDao 老师开了111分钟 目标方法sleep:cglib代理结束... 目标方法sleep:cglib代理开始... 真实代理对象:class com.zking.hujianze.proxy.demo2.TeacherDao$$EnhancerByCGLIB$$ebe7c940 目标对象:class com.zking.hujianze.proxy.demo2.TeacherDao 老师开了222分钟 目标方法sleep:cglib代理结束...
Cglib和jdk动态代理的区别:
1,Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
2,Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
装饰者模式Decorator:
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性。
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性。
结构:
抽象构件角色:定义一个抽象接口以规范准备接收附加责任的对象。
具体构件角色:实现抽象构件,通过装饰角色为其添加一些职责。
抽象装饰角色:继承或实现抽象构件,并包含具体构件的实例,可以通过子类扩展具体构件的功能。
具体装饰角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
示例:单体咖啡与调味组合的单体饮料计价
Component:组件(主体)
ConcreteComponent:被装饰者
Decorator:装饰者
注意:ConcreteComponent、Decorator都会实现或继承Component
package com.zking.hujianze.decorator;
public abstract class Drink {
protected double price;
protected int n;
protected DrinkSeasoning seasoning;
public abstract double getPrice();
}
abstract class Coffee extends Drink { }
abstract class Juice extends Drink { }
class ChinaCoffee extends Coffee{
ChinaCoffee(double price,int n){ this.price = price;this.n = n; }
@Override
public double getPrice() { return this.price*this.n+this.seasoning.getPrice(); }
}
package com.zking.hujianze.decorator;
public interface DrinkSeasoning { public abstract double getPrice();}
class ADrinkSeasoning implements DrinkSeasoning{
protected double price;
protected int n;
ADrinkSeasoning(double price,int n){ this.price = price;this.n = n; }
@Override
public double getPrice() { return this.price*this.n; }
}
class BDrinkSeasoning implements DrinkSeasoning{
private double price;
protected int n;
BDrinkSeasoning(double price,int n){ this.price = price;this.n = n; }
@Override
public double getPrice() { return this.price*this.n; }
}
以下输出为:
中式咖啡1份+A调料2份,最终价格为:10.0
package com.zking.hujianze.decorator;
public class Client {
public static void main(String[] args) {
ChinaCoffee chinaCoffee = new ChinaCoffee(6, 1);
ADrinkSeasoning aDrinkSeasoning = new ADrinkSeasoning(2, 2);
chinaCoffee.seasoning = aDrinkSeasoning;
System.out.println("中式咖啡1份+A调料2份,最终价格为:" + chinaCoffee.getPrice());
}
}
问题1:如果下单中式咖啡1份+A调料3份+B调料2份,计算出最终的价格,那代码该怎么改动呢?
问题2:在原有的咖啡订单下,追加B调料2份,计算出最终的价格,那代码该怎么改动呢?
使用装饰模式进行设计:
package com.zking.hujianze.decorator.demo2;
public abstract class Drink {
protected double price;
protected int n;
public abstract double getPrice();
}
abstract class Coffee extends Drink { }
abstract class Juice extends Drink { }
class ChinaCoffee extends Coffee {
ChinaCoffee(double price, int n) { this.price = price;this.n = n; }
@Override
public double getPrice() {
return this.price * this.n;
}
}
package com.zking.hujianze.decorator.demo2;
public class DecoratorDrink extends Drink {
private Drink drink;
public DecoratorDrink(Drink drink, double price, int n) {
this.drink = drink;
this.price = price;
this.n = n;
}
@Override
public double getPrice() {
return this.price * this.n + drink.getPrice();
}
}
class ADecoratorDrink extends DecoratorDrink {
public ADecoratorDrink(Drink drink, double price, int n) {
super(drink, price, n);
}
}
class BDecoratorDrink extends DecoratorDrink {
public BDecoratorDrink(Drink drink, double price, int n) {
super(drink, price, n);
}
}
package com.zking.hujianze.decorator.demo2;
public class Client {
public static void main(String[] args) {
ChinaCoffee chinaCoffee = new ChinaCoffee(10,1);
//假定A类调料2元一份,B类调料3元一份
Drink order = new ADecoratorDrink(chinaCoffee, 2, 2);
System.out.println("中式咖啡1份+A调料2份,最终价格为:"+order.getPrice());
//问题1:如果我要下单中式咖啡1份+A调料3份+B调料2份,计算出最终的价格,那代码该怎么改动呢?
order = new ADecoratorDrink(order,2,1);
System.out.println("中式咖啡1份+A调料3份,最终价格为:"+order.getPrice());
order = new BDecoratorDrink(order,3,2);
System.out.println("中式咖啡1份+A调料3份+B调料2份,最终价格为:"+order.getPrice());
//问题2:在原有的咖啡订单下,追加B调料2份,计算出最终的价格,那代码该怎么改动呢?
order = new BDecoratorDrink(order,3,2);
System.out.println("中式咖啡1份+A调料3份+B调料4份,最终价格为:"+order.getPrice());
}
}
以下输出为:
中式咖啡1份+A调料2份,最终价格为:14.0 中式咖啡1份+A调料3份,最终价格为:16.0 中式咖啡1份+A调料3份+B调料2份,最终价格为:22.0 中式咖啡1份+A调料3份+B调料4份,最终价格为:28.0
要点:
1.装饰者对象和被装饰者对象有相同的超类型。
2.可以用一个或多个装饰者包装一个对象。
3.装饰者可以在被装饰者行为之前或之后加上自己的行为,以达到特定的目的。
4.对象可以在任何时候被装饰。可以在运行时动态的、不限量的用装饰者来装饰对象。
5.装饰者利用继承来达到“类型匹配”,而不是利用继承“获得行为”。装饰者能够取代被装饰者。
6.将装饰者与组件组合时,就是在加入新的行为。新的行为并不是通过继承得来,而是通过组合对象得来的。
行为型模式
后续补发。。。。



