国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php框架 > 框架设计 > 设计模式之禅——门面模式

设计模式之禅——门面模式

来源:程序员人生   发布时间:2017-02-24 11:23:23 阅读次数:2940次

门面模式【Facade Pattern】也叫外观模式,是1种比较经常使用的封装模式,其定义以下:

【要求1个子系统的外部与其内部的通讯必须通过1个统1的对象进行。门面模式提供1个高层次的接口,使得子系统更容易使用】

门面模式重视“统1的对象”,也就是提供了1个访问子系统的接口,除这个接口不允许有任何访问子系统的行动产生。

门面模式的系统类图以下:

这里写图片描述

类图就是这么简单,但是意义其实很复杂

Subsystem Classes 是所有子系统所有类的简称,它可能代表1个类,也可能代表几10个对象的集合。不管多少对象,我们都将他们化为子系统的范畴,结构如图:

这里写图片描述

【不管子系统有多麻烦,外部只能通过这个【Facade——门面对象】来进行通讯】

1般情况下,Facade会将所有从客户端发来的要求委派到相应的子系统去,也就是说该角色没有实际的 业务逻辑,是1个拜托类。

下面是门面模式的通用源码

//子系统源代码
public class ClassA{
    public void doSomethingA(){
        //业务逻辑
    }
}
public class ClassB{
    public void doSomethingB(){
        //业务逻辑
    }
}
public class ClassC{
    public void doSomethingC(){
        //业务逻辑
    }
}
//门面对象
public class Facade{
    //被拜托的对象
    private ClassA a = new ClassA();
    private ClassB b = new ClassB();
    private ClassC c = new ClassC();
    //提供给外部访问的方法
    public void methodA(){
        this.a.doSomethingA();
    }
    public void methodB(){
        this.b.doSomethingB();
    }
    public void methodC(){
        this.c.doSomethingC();
    }
}

下面用1个例子来看1下具体的门面模式

例子:【我要投递信件】

我们都写过纸质的信件,比如给女朋友写情书甚么的。写信的进程大家应当都记得——先写信的内容,然后写信封,在把信放到信封里,封好,投递到信箱中进行投递。虽然简单,但是这4个步骤都是不可或缺的!

首先我们看如果不使用门面模式应当是怎样实现的

public interface ILetterProcess {
    //首先要写信的内容
    public void writeContext(String context);
    //其次写信封
    public void fillEnvelope(String address);
    //然后邮递
    public void letterInotoEnvolope();
    //然后邮递
    public void sendLetter();
}
public class LetterProcessImpl implements ILetterProcess {
    @Override
    public void writeContext(String context) {
        System.out.println("填写信的内容... " + context);
    }

    @Override
    public void fillEnvelope(String address) {
        System.out.println("填写收信人的姓名和地址..." + address);
    }

    @Override
    public void letterInotoEnvolope() {
        System.out.println("把信放到信封中...");
    }

    @Override
    public void sendLetter() {
        System.out.println("邮递信件...");
    }
}
public class Client {
    public static void main(String[] args) {
        ILetterProcess letterProcess = new LetterProcessImpl();
        letterProcess.writeContext("Hello, It's me, do you know Who I am? I'm your old lover.");

        letterProcess.fillEnvelope("Happy Road No. 666, God Province, Heaven");                                                 

        letterProcess.letterInotoEnvolope();

        letterProcess.sendLetter();
    }
}
Output:
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
把信放到信封中...
邮递信件...

*/

上面的代码与高内聚的要求相差甚远,更不说迪米特原则和接口隔离原则了。

怎样办呢?

邮局出了新的业务,你告知我信的内容和地址,其余的我帮你弄定。

加了1个邮局的类

public class ModenPostOffice {
    //这就是门面对象
    private ILetterProcess letterProcess = new LetterProcessImpl();
    public void sendLetter(String context, String address){
        letterProcess.writeContext(context);
        letterProcess.fillEnvelope(address);
        letterProcess.letterInotoEnvolope();
        letterProcess.sendLetter();
    }
}

修改场景类

public class Client {
    public static void main(String[] args) {
        ModenPostOffice modenPostOffice = new ModenPostOffice();
        String context = "Hello, It's me, do you know Who I am? I'm your old lover.";
        String address = "Happy Road No. 666, God Province, Heaven";
        modenPostOffice.sendLetter(context, address);
    }
}
//Output
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
把信放到信封中...
邮递信件...
*/

下面我们要通过1个要求来看1下门面模式的优点:

要求:【新建发送之前请先检查信件是不是安全】

//增加了检查信件的Police类
public class Police {
    public void checkletter(ILetterProcess letterProcess){
        System.out.println(letterProcess + " 信件已被检查过了...");
    }
}
//修改ModenPostOffice
public class ModenPostOffice {
    //这就是门面对象
    private ILetterProcess letterProcess = new LetterProcessImpl();
    private Police letterPolice = new Police();
    public void sendLetter(String context, String address){
        letterProcess.writeContext(context);
        letterProcess.fillEnvelope(address);
        letterPolice.checkletter(letterProcess);
        letterProcess.letterInotoEnvolope();
        letterProcess.sendLetter();
    }
}

场景类完全1样

//Output
/**
填写信的内容... Hello, It's me, do you know Who I am? I'm your old lover.
填写收信人的姓名和地址...Happy Road No. 666, God Province, Heaven
com.sdkd.LetterProcessImpl@74a14482 信件已被检查过了...
把信放到信封中...
邮递信件... 
*/

可以看到这个新的要求对客户是透明的,他甚么都不用管,只是负责告知邮局内容和地址就能够了。

不改变子系统对外暴露的接口 、方法,只改变内部的处理逻辑,其他兄弟模块的调用产生了想要得到结果,这确切是1个非常好的设计。这就是门面模式。

最后的UML图以下,层次模块很明显

这里写图片描述

门面模式的优点:

1、减少系统的相互依赖
2、提供了灵活性
3、提供了安全性

门面模式的缺点:

门面模式不符合开闭原则,1旦出错风险很大。

门面模式的使用处景:

1、为1个复杂的模块或子系统提供1个供外界访问的接口
2、子系统相对独立,对外界来讲访问只要暗箱操作就能够
3、预防低水平人员带来的风险分散。

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生