你可能看到标题会觉得这两个模式有啥关系啊,很好,这两个模式确实没有关系哈哈,但是我今天把这两个模式放在一起说还是有原因的。
举个栗子
装饰模式
Component:抽象构建
ConcreteComponent:具体构建类(被装饰类)
Decorator:装饰类
interface Component{
void method();
}
class ConcreteComponent implements Component{
public void method(){
System.out.println("method");
}
}
class Decorator implements Component{
private Component component;
public Decorator(Component component){
this.component = component;
}
public void method(){
System.out.println("PreDecorate");
component.method();
System.out.println("PostDecorate");
}
}
public class Test {
public static void main(String args[]){
ConcreteComponent concreteComponent = new ConcreteComponent();
Decorator decorator = new Decorator(concreteComponent);
decorator.method();
}
}
代理模式
interface Subject{
void request();
}
class RealSubject implements Subject{
public void request(){
System.out.println("request");
}
}
class Proxy implements Subject{
private RealSubject realSubject;
public Proxy(){
this.realSubject = new RealSubject();
}
public void request(){
System.out.println("PreProcess");
realSubject.request();
System.out.println("PostProcess");
}
}
public class ProxyDemo {
public static void main(String args[]){
Proxy p = new Proxy();
p.request();
}
}
栗子分析
上面的栗子中,第一个是装饰模式,第二个代理模式,在接口的实现上面以至于整个代码上面几乎都没有多大的差别。以至于很多刚开始学习设计模式的同学看的有点晕,分不清两个的区别在哪。我们先来看下代码上的区别在哪:
第一处区别
在客户端代码(也就是此处的测试代码)中,装饰模式先创建一个具体构建类(被装饰类),然后作为参数通过构造器创建一个装饰类。而代理模式中,直接创建一个代理类,此处你看不见被代理类是什么,也就是说被代理类对于客户端是透明的。
第二处区别
装饰类中,将客户端代码中传递过来了的被装饰类赋给装饰类持有的抽象构建引用
代理类中,持有的是被代理类引用,且在构造函数中创建一个被代理类实例。
比较分析
这两个区别说的仅仅是第一个栗子中代码上的区别,但是至少可以看出来一点,被代理对象对于客户端来说是透明的。
再举一栗
装饰模式
interface Arrangement {
public void show();
}
class Person implements Arrangement {
private String name;
public Person(String name){
this.name = name;
}
@Override
public void show() {
System.out.println(name + "的搭配:");
}
}
abstract class Dress implements Arrangement {
private Arrangement arrangement;
public void Dress(Arrangement arrangement){
this.arrangement = arrangement;
}
@Override
public void show() {
if (arrangement != null){
arrangement.show();
}
}
}
class DKC extends Dress {
@Override
public void show() {
super.show();
System.out.println("大裤衩");
}
}
class PX extends Dress {
@Override
public void show() {
super.show();
System.out.println("皮鞋");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person("小明");
DKC dkc = new DKC();
PX px = new PX();
dkc.Dress(person);
px.Dress(dkc);
px.show();
}
}
代理模式
Girl:被追求的妹子
GiveGift:送礼物
Suitor:真实的追求者(由于比较害羞,找了一个代理帮自己追)
Proxy:代理类
class Girl {
private String name;
public Girl(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
interface GiveGift {
public void GiveFlowers();
public void GiveDove();
public void GiveDolls();
}
class Suitor implements GiveGift {
private Girl girl;
public Suitor(Girl girl){
this.girl = girl;
}
@Override
public void GiveFlowers() {
System.out.println(girl.getName()+",送你花!");
}
@Override
public void GiveDove() {
System.out.println(girl.getName()+",送你巧克力!");
}
@Override
public void GiveDolls() {
System.out.println(girl.getName()+",送你洋娃娃!");
}
}
public class Proxy implements GiveGift {
private Suitor suitor;
public Proxy(Girl girl){
this.suitor = new Suitor(girl);
}
@Override
public void GiveFlowers() {
suitor.GiveFlowers();
}
@Override
public void GiveDove() {
suitor.GiveDove();
}
@Override
public void GiveDolls() {
suitor.GiveDolls();
}
public static void main(String[] args) {
Girl girl = new Girl("marry");
Proxy proxy = new Proxy(girl);
proxy.GiveDolls();
proxy.GiveDove();
proxy.GiveFlowers();
}
}
结合这个栗子再来说明一下两个模式分别是什么。
装饰模式是什么
装饰模式可以说就是在已有功能的基础上添加更多的功能,把每个要添加的功能都放在一个单独的类中,并让这个类包装被装饰对象,然后在执行特定任务时,客户端代码就可以在运行时根据需要自由组合,按顺序地使用这些装饰功能。
代理模式是什么
代理模式就是为一个对象提供一个代理并控制着对这个对象的访问。并且被代理对象对于客户端代码是透明的。就像最后这个栗子中,客户端代码并不知道真实的追求者是谁。代理类控制着真实追求着的访问,当然也可以添加一些功能什么的(就像装饰模式那样)。
总结
现在理解了两个模式之后,就会发现两个模式的目的并没有什么关联。完全没必要纠结像第一个栗子中的代码相似问题。要说真实应用的话,JDK的IO包中的BufferedInputstream就是一个装饰类,Spring的AOP就用的是代理,不过是动态代理而已。
最后推荐学习设计模式的小伙伴们有兴趣可以看一下《大话设计模式》这本书,通过讲故事的形式把道理给讲明白了,个人还是觉得蛮好的。