写完上一篇之后有小伙伴问我有没有写过代理模式,想看看我的理解。原本我的设计模式系列是按照创建型-行为型-结构型的顺序写下去的,既然小伙伴诚心诚意了,我就大发慈悲的穿插一篇代理模式。开玩笑,题外话。
说起代理模式,就不由得想起经纪人,说起经纪人,就想起了…对,没错就是“许三多”。这就有点邪恶了~甭八卦了,入正题。
经纪人的角色就相当于一个代理,要找到明星就先经过经纪人,经纪人负责给明星接拍电影把关、活动捞金,这就是为什么要用到代理的原因,抛开其他繁琐的事务,专注被代理人的业务逻辑,减轻被代理人的负担。so,带着一点点罪恶感来看看什么是代理模式。
一、代理模式
定义
为其它对象提供一个代理对象,并由代理对象控制这个对象的访问。
特点
1)很直接的,实现同一个接口或者继承同一个抽象类。
2)代理对象控制对被代理对象的访问。
UML
代理模式UML图
这是代理模式的通用UML,涉及到的角色如下所示:
– 抽象主题角色:定义了被代理角色和代理角色的共同接口或者抽象类。
– 被代理角色:实现或者继承抽象主题角色,定义实现具体业务逻辑的实现。
– 代理角色:实现或者继承抽象主题角色,持有被代理角色的引用,控制和限制被代理角色的实现,并且拥有自己的处理方法(预处理和善后)
二、代理模式实战
首先是抽象主题角色:
public interface Subject {
public void movie();
}复制代码
很简单,单纯定义了movie方法,下面看被代理角色的实现:
public class Star implements Subject {
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":经纪人接了一部电影,我负责拍就好");
}
}复制代码
被代理角色实现抽象主题角色,专注实现被代理角色的业务逻辑。继续看代理角色:
public class Agent implements Subject {
private Subject star;
public Agent(Subject star) {
this.star = star;
}
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":剧本很好,这部电影接下了");
star.movie();
}
}复制代码
代理角色持有被代理角色的引用,要访问被代理角色必须通过代理,负责被代理角色本职之外的职能,并且具有准入和过滤的功能。最后来看客户端的实现:
public class Client {
public static void main(String[] args) {
Subject star = new Star();
Subject proxy = new Agent(star);
proxy.movie();
}
}复制代码
表面上是调用了代理的方法,实际的执行者其实是被代理角色Star,看看结果就知道:
Agent:剧本很好,这部电影接下了
Star:经纪人接了一部电影,我负责拍就好
上面是代理模式其中的一种实现方式,主要在代理角色Agent中指定了被代理角色Star,意思是经纪人大喊一声“嘿~兄弟,你是我的了!”。
下面看代理模式的另一种实现方式,先看抽象主题角色代码:
public interface Subject {
public void movie();
// 指定代理
public Subject getAgent();
}复制代码
增加了指定代理的方法getAgent,再来看被代理角色和代理角色代码:
// 被代理角色
public class Star implements Subject {
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":经纪人接了一部电影,我负责拍就好");
}
@Override
public Subject getAgent() {
return new Agent(this);
}
}
// 代理角色
public class Agent implements Subject {
private Subject star;
public Agent(Subject star) {
this.star = star;
}
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":剧本题材很好,这部电影接下了");
star.movie();
}
@Override
public Subject getAgent() {
return this;
}
}复制代码
重点看被代理角色getAgent方法,方法里面指定了Agent为代理,而Agent的getAgent并没有指定代理。下面看客户端代码实现:
public class Client {
public static void main(String[] args) {
Subject star = new Star();
Subject proxy = star.getAgent();
proxy.movie();
}
}复制代码
在客户端通过getAgent得到指定代理角色,由代理来控制star对象。
运行的结果的跟上一种方式是一样的。注意,这种方式是客户端直接访问被代理角色,代理由被代理角色指定。前面的一种方式则是客户端不能访问直接访问被代理角色,只能访问代理。但是,无论是哪一种方式,代理模式的实现都是必须经过代理才能访问被代理模式。就比如明星拍电影,不会跳过经纪人直接找到明星,而是经过经纪人再到明星,要不然经纪人这个职位岂不是浪费了。
三、代理模式扩展
代理模式VS装饰者模式
代理模式在讲解了,接下来看装饰者模式,先搞一张装饰者模式的UML图
装饰模式UML图
别坑我读的书少,这明明就是代理模式的UML。没错,装饰者模式和代理模式就是这么相似,包括UML和代码实现,甚至可以是一模一样。不信?来看装饰者模式的代码,这里我只给出简单代码:
// 抽象构件
public interface Component {
public void movie();
}
// 具体构件,实现Component,要被装饰的
public class Star implements Component {
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":化了妆迷倒一片妹纸,拍起来电影特别带劲");
}
}
// 装饰者,装饰具体构件
public class ConcreteDecorator implements Component {
private Component star;
public ConcreteDecorator(Component concreteComponent) {
this.star = concreteComponent;
}
@Override
public void movie() {
System.out.println(getClass().getSimpleName() + ":拍电影各种道具加身,还得化妆");
star.movie();
}
}
public class Client {
public static void main(String[] args) {
Subject star = new Star();
Subject proxy = new Agent(star);
proxy.movie();
}
}复制代码
运行客户端代码,结果如下:
ConcreteDecorator:拍电影各种道具加身,还得化妆
Star:化了妆迷倒一片妹纸,拍起来电影特别带劲
哈哈哈哈,傻傻的分不清是装饰者还是代理模式了吧!UML一样,就算代码的实现也可以一样,就把结果改了改。下面总结了它俩的异同:
相同点
都需要实现同一个接口或者继承同一个抽象类,并且代理角色和装饰角色都持有被代理角色和构件角色的引用。
两种模式都可以在被代理角色和具体构件角色的业务方法前后添加自己的方法。额…说了等于没说。
不同点
代理模式重点在于控制对象的行为,而装饰模式侧重于增加对象的职能(当然也可以削弱)。看完这句话立马晕菜,到底是怎么才叫控制行为和增加职能?设计模式离不开面对对象思想,用面向对象的思想思考这个问题。代理模式是对整个对象的行为控制和限制,而非针对功能,跟装饰模式不一样,装饰模式针对的是对象职能上的加强,也就是属性或者方法。
通俗的讲,它们俩根本的区别是目的性不一样,也就是使用场景。比如公司老板,为了更好的管理公司会请做行政、财务的人回来帮忙处理公司事务,把事情整理好了,有必要的事情才到达老板那,这就是代理。如果是装饰呢,就是往老板身上加职能,不仅提供财力,还要懂行政管理,财务会计,甚至要会敲代码,可以这么做,但并不符合实际使用场景。
四、代理模式的优缺点
优点
1)良好的扩展性。修改被代理角色并不影响调用者使用代理,对于调用者,被代理角色是透明的。
2)隔离,降低耦合度。代理角色协调调用者和被代理角色,被代理角色只需实现本身关心的业务,非自己本职的业务通过代理处理和隔离。
缺点
1)增加了代理类,实现需要经过代理,因此请求速度会变慢。
总结
代理模式有静态和动态两种方式,这篇文章的代理模式都是使用静态代理,动态代理在往后设计模式的扩展会补上。这里不讲解动态代理首先是因为重点在于把代理模式核心阐述清楚,再者是动态代理用到的篇幅会较长,所以放到之后静态代理和动态代理的对比扩展一起讲解比较合适。另外,注意代理模式和装饰者模式的区别,从网上看到了一堆相关的资料,有的说是构造方法不同,有的就直接抛出一句控制行为和增加职能虚无缥缈的阐述,都没有说清两者的区别,看完后还是一脸的懵。这篇文章我给出了自己的它俩见解,有不同看法的小伙伴也可以给我意见。下一篇模板方法模式,您的点赞和关注是我的动力哦,see you!
设计模式Java源码GitHub下载:https://github.com/jetLee92/DesignPattern
AndroidJet的开发之路