本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
其他设计模式介绍
创建型:
工厂方法
抽象工厂
原型
结构型:
适配器
桥接模式
组合模式
装饰模式
外观模式
享元模式
代理模式
行为型:
职责链
命令
解释器
迭代器
中介者
备忘录
状态模式
策略模式
模板方法
访问者
定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
静态代理
静态代理的模式在平时生活中也很常见,比如买火车票这件小事,黄牛相当于是火车站的代理,我们可以通过黄牛或者代售点进行买票行为,但只能去火车站进行改签和退票,因为只有火车站才有改签和退票的方法。
在代码实现中相当于为一个委托对象realSubject提供一个代理对象proxy,通过proxy可以调用realSubject的部分功能(买票),并添加一些额外的业务处理(收取手续费),同时可以屏蔽realSubject中未开放的接口(改签和退票)。
// 委托类接口
interface Subject {
fun request()
}
// 具体委托类
class RealSubject : Subject {
override fun request() {
println("RealSubject")
}
fun run(){}
}
// 代理类
class Proxy(private val subject: Subject) : Subject {
override fun request() {
println("begin")
subject.request()
println("end")
}
}
fun main() {
val subject = RealSubject()
val p = Proxy(subject)
p.request()
}
复制代码
- RealSubject 是委托类,Proxy 是代理类;
- Subject 是委托类和代理类的接口;
- request() 是委托类和代理类的共同方法;
- RealSubject 中有未公开的方法
- 静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
动态代理
- 代理对象不需要实现目标对象的接口。
- 代理对象的生成,使用的是Java的API,动态的在内存中构件代理对象(这需要我们指定创建代理对象/目标对象的接口的类型)。
- 动态代理也叫做JDK代理、接口代理。
- 相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等,
下面通过一个例子看看如何实现jdk动态代理。
// 目标对象接口
interface IUserDao {
fun save()
}
// 目标对象类
class UserDao : IUserDao {
override fun save() {
println("---------已经保存数据----------")
}
}
/**
* 创建动态代理对象
* 动态代理对象不需要实现接口,但是需要指定接口类型
*/
class ProxyFactory(private val target: Any) {
//给目标对象生成代理对象
val proxyInstance: Any
get() = Proxy.newProxyInstance(
target.javaClass.classLoader, target.javaClass.interfaces
) { proxy, method, args ->
println("Begin Transaction")
//执行目标对象方法
val returnValue = method.invoke(target, *args)
println("Commit Transaction")
returnValue
}
}
fun main() {
//目标对象
val userDao: IUserDao = UserDao()
//原始类型 class com.sschen.proxy.UserDao
println(userDao.javaClass)
//给定目标对象,动态创建代理对象
val proxy = ProxyFactory(userDao).proxyInstance as IUserDao
//代理对象类型 class com.sun.proxy.$Proxy0
println(proxy.javaClass)
proxy.save()
}
复制代码
从上面的代码可以看出,动态代理对象不需要实现目标对象接口,但是目标对象一定要实现接口,否则不能使用动态代理。
应用场景
说完对动态代理,下面来说一下代理模式的应用场景吧。
相信我们在开发的过程都会去请求网络,如果我们采用 Java 自带的网络框架去请求网络就会显得很臃肿,因此我们一般会选用一些网络请求框架进行封装,最后进行调用,整个框架如图:
在这种网络架构下,看起来很完美,对网络框架都进行了封装,当应用层需要请求网络时调用一下工具层的 post 方法,最后通过框架的具体方法去请求网络。
如果在这种架构下需要更换网络框架会发生什么问题呢?
虽然对每个框架都进行了封装,但是每个框架的入参以及其他返回参数等都不一样,这就导致了工具层的 post 方法需要做出对应的修改,同时应用层在调用的地方也需要做出相应的修改,这显然是不符合开闭原则的。
而代理模式就可以很好的解决这个问题,在上面这种架构下的工具层下面在加多一层代理层,也就是一个网络请求接口,而在工具层中的 post 方法也实现了这个接口,在构造方法中传入一个代理对象,而不同的框架也去实现这个接口,在实现方法中去做不同的请求方法,架构如下图:
代理层是一个接口(post),如果有多个框架,则每个框架都去实现该接口(post),在实现方法中做每个框架的不同的请求操作。
应用层也去实现代理层的接口,构造方法传入的代理层接口对象,在接口的实现方法中调用 传入的代理层接口对象 的post方法
这就印证了开闭原则
近期评论