今天看一下一个比较简单而好用的设计模式,门面模式,我缩写的思路都是按照《设计模式之禅》一本书上的讲解,再加上自己一些想法。
门面模式定义
门面模式(Facade Pattern)也叫做外观模式,要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层的接口,使得子系统更易于使用。
门面模式包含两个角色,如一下类图
很简单的类图,一个门面角色,一个子系统角色,
(Facade)门面角色:客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。改角色没有实际的业务逻辑,只是一个委托类;
(Subsystem)子系统角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统不知道门面的存在
门面模式简单实现
创建子系统1:
package design.facade;
public class Subsystem1 {
public void subSystem1Method(String str){
System.out.println("Subsystem1:"+str);
}
}
创建子系统2:
package design.facade;
public class Subsystem2 {
public void subSystem2Method(String str){
System.out.println("Subsystem2:"+str);
}
}
创建门面Facade:
package design.facade;
public class Facade {
private Subsystem1 s1 = new Subsystem1();
private Subsystem2 s2 = new Subsystem2();
public void subSystem1(String str){
s1.subSystem1Method(str);
}
public void checkSystem1(String str){
s2.subSystem2Method(str);
}
}
测试:
package design.facade;
public class TestMain1 {
public static void main(String[] args) {
Facade f = new Facade();
f.subSystem1("门面模式子系统1被调用了。。。");
f.subSystem2("门面模式子系统2被调用了。。。");
}
}
结果:
Subsystem1:门面模式子系统1被调用了。。。
Subsystem2:门面模式子系统2被调用了。。。
例子很简单,就是把两个类聚合到另外一个类,然后通过这个类访问他们各自的方法。门面对象是访问子系统内部的唯一通道,不管子系统内部多么乱,只要有门面对象在,就可以通过门面调用。
不过这样远远不够,如果现在需要加一个功能,检查输入的字符串是否包含脏字,比如 “我靠”,“贱人”之类的敏感词,我们需要替换为**,很容易想到的是在打印的时候加判断,或者在门面里面加判断,比如这样:
package design.facade;
public class Facade {
private Subsystem1 s1 = new Subsystem1();
private Subsystem2 s2 = new Subsystem2();
public void subSystem1(String str){
if(str.contains("我靠")){
str = str.replace("我靠", "**");
}
s1.subSystem1Method(str);
}
public void subSystem2(String str){
s2.subSystem2Method(str);
}
}
这样确实可以实现,但是这样很不靠谱,这样做的话门面就参与了业务逻辑,门面对象只是一个访问子系统的一个路径,它不应该也不能参与具体的业务逻辑,否则就会产生一个倒依赖的问题:子系统必须依赖门面才能被访问。门面的职责应该是单一的,酱紫也破坏了系统的封装性。
我们可以简历一个分装类,把业务逻辑封装起来提供给门面对象:
检查脏话的分装类(或者特定权限处理,检查之类的):
package design.facade;
public class CheckChart {
public CheckChart() {
}
private Subsystem1 s1 = new Subsystem1();
public void subSystem1(String str){
if(str.contains("我靠")){
str = str.replace("我靠", "**");
}
s1.subSystem1Method(str);
}
}
修改门面:
package design.facade;
public class Facade {
private Subsystem1 s1 = new Subsystem1();
private Subsystem2 s2 = new Subsystem2();
private CheckChart cc = new CheckChart();
public void checkSubSystem1(String str){
cc.subSystem1(str);
}
public void subSystem1(String str){
s1.subSystem1Method(str);
}
public void subSystem2(String str){
s2.subSystem2Method(str);
}
}
通过以上的修改,门面的职责就很单一没有参与业务逻辑,并且子系统(子类s1 s2)也没做任何修改,外部访问也不用修改,门面不应该经常变化,如果业务逻辑变化,封装就可以,对外面来说还是同一个门面。
当然,我写的代码只是为了说明这个门面模式,在实际开发中没这么简单,可能会是多个门面,这很正常,门面也不可能太庞大,我们需要根据子系统的功能划分门面等。
门面模式优点
比如我们的项目已经做好了,然后要开发新功能,来了一些菜鸡,写的代码一坨一坨的没法读,也不想读,那我们就可以建立一个门面,将他们的类聚合进来,我们只在乎干净清爽的门面就可以;
还有:比如我们创建了很多子系统了,一些有特定算法的子系统需要按顺序去执行或者赋值,这样的话我们就必须很熟悉子系统的内不结构,如果不熟悉,乱调用的话可能会出意想不到的问题,这里我们就可以创建一个门面,将特定算法的方法封装到一个类里面然后聚合到门面,我们通过门面访问只需要传入需要的参数,而我们也没必要知道子系统的结构以及算法;
减少系统的互相依赖
因为门面,外部可以不用直接访问子系统,解耦合
提高了灵活性
依赖少了,灵活性就高了,不管子系统内部如果改变,门面依然是以前的门面
提高了安全性
只容许访问门面开通的方法
门面模式缺点
最大的缺点就是不符合,对修改关闭,对扩展开放,如果门面出问题了,没有其它办法,只能修改门面代码。
到这里门面模式都完了,只要记住两点就行
1.门面不要参与子系统内部的业务逻辑
2.门面为我们提供了访问子系统的接口
设计模式虽然不是一门技术,但是对我们平时编程与阅读API很有帮助,个人也只是皮毛重点还是应用,欢迎大神们加群一起探讨 群号:167014883