设计模式-问题-门面模式+装饰者模式+代理模式
代理模式
为什么有静态代理?他解决什么问题?为什么又要使用动态代理,说说具体使用场景体会他的好处。
代理主要还是想在类不被修改代码的情况下做一些增强。
静态代理运行在编译期,也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了
静态代理主要有几个缺点
一个接口只能服务于一种类型的类,如果要代理的方法很多,势必要为每一种方法都进行代理,在程序规模稍大时静态代理代理类就会过多会造成代码混乱
如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度。 基于上述两个问题,动态代理诞生了
明白了动态代理使用场景,再说说具体动态代理怎么实现的?有哪些实现方式?
动态代理是在程序运行时,通过反射获取被代理类的字节码内容用来创建代理类
一种是通过JDK的动态代理(基于实现接口)
$Proxy0
类似于装饰器模式
一种是通过CGLIB的动态代理(基于继承)
Enhance
需要注意final的方法和类没法被CGLIB代理
JDK动态代理跟CGLIB动态代理的区别。
JDK动态代理是基于实现接口的的
CGLIb是基于继承的
final的方法和类无法被代理
由课中动态数据源的例子有没有更深刻体会到动态代理的好处?
动态代理能够帮助我们动态的给类增强一些功能,而不需要修改类,这是一系列横切的操作。
能够服务于各种类型的类
门面模式
想一想什么场景下考虑使用门面模式
一个子系统比较复杂时,比如算法或者业务比较复杂,就可以封装出一个或多个门面出来,项目的结构简单,而且扩展性非常好。
对于一个较大项目,为了避免人员带来的风险,也可以使用门面模式,技术水平比较差的成员,尽量安排独立的模块,然后把他写的程序封装到一个门面里,尽量让其他项目成员不用看到这些人的代码,看也看不懂,我也遇到过一个“高人”写的代 码,private方法、构造函数、常量基本都不用,你要一个public方法, 好,一个类里就一个public方法,所有代码都在里面,然后你就看吧, 一大坨程序,看着就能把人逼疯。使用门面模式后,对门面进行单元测试,约束项目成员的代码质量,对项目整体质量的提升也是一个比较好 的帮助。
装饰者模式
仔细对比一下装饰者模式和代理模式结构图,想一想你怎么区分它们,从这里给你什么启发。
装饰器主要强调的是自己,扩展的是自己的能力,并且是对继承的扩展
代理模式则是为了实现对象的控制,提供一个代理对象出来,通过代理对象来控制原有对象的引用
装饰模式是为装饰的对象增强功能;而代理模式对代理的对象施加控制,但是并不象本身的功能进行增强;
分析一下java IO代码
new BufferedReader(new FileReader(""))
为什么可以层层包装,画出类图或从代码层面描述怎么实现的

可以看到在BufferedReader构造方法中可以传入Reader那么在调用的时候就会给其包装一层
private void fill() throws IOException {
//这一段都是包装一层走的Buffer
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
//FileReader#read
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
Last updated