外观模式

本文详细介绍了外观模式的概念、结构、实现方式及其应用场景。通过一个代码生成子系统的实例,展示了如何使用外观模式来简化客户端与子系统之间的交互,降低耦合度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

外观模式
定义:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口是的这一子系统更加容易使用。
结构和说明:
这里写图片描述

Facade:定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块,从而吧客户的请求代理给适当的子系统对象。
模块:接受Facade对象的委派,真正实现功能,各个模块之间可能有交互。注意,Facade对象知道各个模块,但是各个模块不应该知道Facade对象。

举例:

//示意生成表现层的模块
public class Presentation {
    public void generate() {
        ConfigModel cm = ConfigManager.getInstance().getConfigData();
        if (cm.isNeedGenPresentation()) {
            System.out.println("正在生成表现层代码文件");
        }
    }
}
//示意生成逻辑层的模块
public class Business {
    public void generate() {
        ConfigModel cm = ConfigManager.getInstance().getConfigData();
        if (cm.isNeedBusiness()) {
            System.out.println("正在生成逻辑层代码文件");
        }
    }
}
//示意生成数据层的模块
public class DAO {
    public void generate() {
        ConfigModel cm = ConfigManager.getInstance().getConfigData();
        if (cm.isNeedDAO()) {
            System.out.println("正在生成数据层代码文件");
        }
    }
}
//配置管理
public class ConfigManager {
    private static ConfigManager manager = null;
    private static ConfigModel cm = null;
    private ConfigManager() {
    }
    public static ConfigManager getInstance() {
        if (manager == null) {
            manager = new ConfigManager();
            cm = new ConfigModel();
            //读取配置文件,把值设置到ConfigModel中去
        }

        return manager;
    }
    //获取配置的数据
    public ConfigModel getConfigData() {
        return cm;
    }
}
//示意配置描述的数据Model,真实的配置数据会很多
public class ConfigModel {
    //是否需要生成表现层,默认true
    private boolean needGenPresentation = true;
    //是否需要生成逻辑层,默认true
    private boolean needGenBusiness = true;
    //是否需要生成DAO,默认true
    private boolean needDAO = true;

    //开放getset方法
}

不使用外观模式,客户端这样写

public class Client {
    public static void main(String[] args) {
        //现在没有配置文件,就直接使用默认的配置
        //通常情况下,三层都应该生成,也就是说客户端必须
        //对这些模块都有了解,才能够正确使用它们
        new Presentation().generate();
        new Business().generate();
        new DAO().generate();
    }
}

如果说模块变了,客户端的调用可能也要变化,这是非常糟糕的
存在的问题:客户端为了使用生成代码的功能,需要与生成代码子系统内部的多个模块交互。

使用模式的解决方案:

//代码生成子系统的外观对象
public class Facade {
    //客户端需要的,一个简单的调用代码生成的功能
    public void generate() {
        new Presentation().generate();
        new Business().generate();
        new DAO().generate();
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        new Facade().generate();
    }
}

这样客户端就不需要与模块的内部打交道了,只与Facade打交道

外观模式的目的:
外观模式的目的不是给子系统添加新的功能接口,而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。

Facade是为了让客户端和子系统分别开,实际上是帮客户端转调了这些内部的实现。包装、组合已有的功能,来满足客户端的功能。

使用外观和不使用外观相比有何变化:
Facade方便了客户端的调用、封装了系统内部的细节功能、实现功能的共享和复用。

Facade可以看成是对客户端的接口,当然这个接口不是interface,而是客户端与子系统交互的通道,好比你做出租车,司机相当于Facade,出租车的功能是子系统,我们是客户端,我们不需要自己去驾驶出租车,而是让司机去操作,而我们只说一句到哪,司机就操作一系列的汽车功能比如导航等把我们送到目的地。如果我们自己去驾驶的话就会有压力,我们要做的是要到达目的地,但是为了到达目的地还要学习驾驶汽车,显然很麻烦,在代码中也是如此,客户端要关心的事情太多,要知道各个模块的存在和功能,如果要传参的话它还要了解内部的细节,否则没有办法正确的使用。共享和复用也不难理解,如果有多个客户端,你不能每次都写那三行代码吧,这就好比一辆出租车只能拉同一个人,其余人不能拉,也是不现实的。

那Facade内部不也是这三行代码,不是也就存在这个问题吗
Facade是属于子系统的这一边,本来就应该知道的。

当然了,系统有外观,但是也可以不使用。

外观模式的实现:
1.把外观类当成一个辅助工具类实现,可以定义成单例的。

public class Facade {
    private Facade() {}
    public static void generate() {
        ...
        ...
        ...
    }
}
public class Client {
    main() {
        Facade.generate();
    }
}

2.Facade可以实现成为interface
工厂模式

3.Facade实现成为interface的附带好处
能够有选择性的暴露接口方法,尽量减少模块对子系统外提供的接口方法。

4.Facade的方法实现
Facade的方法实现中,一般是负责把客户端的请求转发给子系统内部的各个模块进行处理,Facade的方法本身并不进行功能的处理,Facade的方法的实现只是实现一个功能的组合调用。

外观模式的优缺点:
1.松散耦合
2.简单易用
3.更好的划分访问的层次
4.过多的或者是不太合理的Facade也容易让人迷惑

外观模式的本质是:封装交互,简化调用;体现了“最少知识原则”

何时选用外观模式:
1.如果你希望为一个复杂的子系统提供一个简单接口的时候,可以考虑使用外观模式,使用外观对象来实现大部分客户需要的功能,从而简化客户的使用
2.如果想要让客户程序和抽象类的实现部分松散耦合,可以考虑使用外观模式,使用外观对象来将这个子系统与它的客户分离开来,从而提高子系统的独立性和可移植性
3.如果构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,也可以松散层次之间的依赖关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值