目录
一:设计模式
- 概念:设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
- 目的:为了代码可重用性,让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
二:设计原则
设计模式就是因为实现了设计原则(面向对象),从而达到了代码复用,增加可维护性的目的。
- 开闭原则(Open Close Principle)
对扩展开发,对修改关闭
在程序需要进行扩展的时候,不能去修改原有的代码 - 里氏替换原则(Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现
里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化。而基类于子类的继承关系就是抽象化的具体实现。
- 依赖倒置原则(Dependence Inversion Principle)
面向接口编程,依赖于抽象/接口,而不依赖于具体实现
这个是开闭原则的基础
- 接口隔离原则(Interface Segregation Principle)
使用多个接口比使用单一接口要好,降低代码的耦合度 - 迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 - 单一职责原则(Single Responsibility Principle)
一个类只做一件事
三:设计模式的分类
总体来说设计模式分为三大类
- 创建型模式,共五种:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
- 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为模式,共十一钟:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问模式、中介者模式、解释器模式。
本章重点-----结构型模式之代理模式
1. 定义:
代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问。
类图:
RealSubject 具体主题角色
是业务逻辑的具体执行者
ProxySubject代理主题角色
它负者对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作
2. 示例:
我们以找中介买二手车为例
1. 静态代理:
/**
* 主要业务
* @author xiyang.ycj
* @since Nov 21, 2019 18:03:23 PM
*/
public interface IBuyer {
void buy();
}
-----------------------------------
/**
* 客户
* @author xiyang.ycj
* @since Nov 21, 2019 17:59:01 PM
*/
public class Buyer implements IBuyer{
@Override
public void buy(){
System.out.println("我要买辆车");
}
}
-----------------------------------
/**
* 中介
* @author xiyang.ycj
* @since Nov 21, 2019 18:01:09 PM
*/
public class ProxyBuyer implements IBuyer{
private Buyer buyer;
public ProxyBuyer(Buyer buyer) {
this.buyer = buyer;
}
@Override
public void buy() {
System.out.println("中介--买车记录---找到车源");
buyer.buy();
System.out.println("中介--买车记录---交易完成--记录业绩");
}
}
-----------------------------------
public class ProxyClient {
@Test
public void staticProxy(){
// 创建一个买家
Buyer buyer = new Buyer();
// 找到一个中介
ProxyBuyer proxyBuyer = new ProxyBuyer(buyer);
proxyBuyer.buy();
}
}
-----------------------------------
中介--买车记录---找到车源
我要买辆车
中介--买车记录---交易完成--记录业绩
静态代理:
优点:可以做到在符合开闭原则的情况下对目标进行功能扩展
缺点:我们得为每一个服务都创建代理类,工作量太大,且一但主要业务发生改变,代理类也得改变
2. JDK动态代理:
/**
* 动态处理器
* @author xiyang.ycj
* @since Nov 21, 2019 18:01:09 PM
*/
public class Dynamic implements InvocationHandler {
private Object target;
public Dynamic(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("中介--买车记录---找到车源");
Object invoke = method.invoke(this.target, args);
System.out.println("中介--买车记录---交易完成--记录业绩");
return invoke;
}
}
-----------------------------------
public class ProxyClient {
@Test
public void dynamicProxy(){
// 创建一个买家
IBuyer buyer = new Buyer();
// 找到一个中介
IBuyer instance = (IBuyer)Proxy.newProxyInstance(Buyer.class.getClassLoader(), new Class[]{IBuyer.class}, new Dynamic(buyer));
instance.buy();
}
}
-----------------------------------
中介--买车记录---找到车源
我要买辆车
中介--买车记录---交易完成--记录业绩
注意Proxy.newProxyInstance()方法接收三个参数:
● ClassLoder loder:指定当前目标对象使用得类加载器,获取加载器得方法是固定得。
● Class<?>[] interfaces:指定目标对象实现得接口的类型,使用泛型方式确认类型。
● InvocationHandler handler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法。
3. CGLIB动态代理:
由于JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,就需要CGLIB了.
CGLIB:采用非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但不能对final修饰的类进行代理(继承)。
/**
* cglib方法拦截
* @author xiyang.ycj
* @since Nov 21, 2019 18:54:48 PM
*/
public class Cglib implements MethodInterceptor {
/* 创建一个子类 */
public <T> T getInstance(Class<T> clazz){
return (T) Enhancer.create(clazz,this);
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("中介--买车记录---找到车源");
Object invokeSuper = methodProxy.invokeSuper(o, objects);// 调用业务类(父类中)的方法
System.out.println("中介--买车记录---交易完成--记录业绩");
return invokeSuper;
}
}
-----------------------------------
public class ProxyClient {
@Test
public void cglibProxy(){
Buyer instance = new Cglib().getInstance(Buyer.class);
instance.buy();
}
}
-----------------------------------
中介--买车记录---找到车源
我要买辆车
中介--买车记录---交易完成--记录业绩
CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。
3.工厂模式的应用
1. 优点:
- 职责清晰。
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。 - 高扩展性
- 智能化
2. 使用场景
- spring aop
- 权限管理
- 事务