09.外观模式设计思想
09.外观模式设计思想
目录介绍
- 01.外观模式基础
- 1.1 外观模式由来
- 1.2 外观模式定义
- 1.3 外观模式场景
- 1.4 外观模式思考
- 1.5 解决的问题
- 02.外观模式实现
- 2.1 罗列一个场景
- 2.2 外观结构
- 2.3 外观基本实现
- 2.4 有哪些注意点
- 2.5 设计思想
- 03.外观实例演示
- 3.1 需求分析
- 3.2 代码案例实现
- 3.3 是否可以优化
- 04.外观模式场景
- 05.外观模式分析
- 5.1 外观模式优点
- 5.2 外观模式缺点
- 5.3 适用环境
- 5.4 模式拓展
- 06.外观代理总结
- 6.1 总结一下学习
- 6.2 更多内容推荐
推荐一个好玩网站
一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网
https://yccoding.com/
01.外观模式基础
1.0 本博客AI摘要
外观模式设计思想:为了解决软件系统中的复杂性和耦合性问题,外观模式提供了一组统一的接口,简化客户端与子系统的交互。主要内容包括外观模式的基础、实现、实例演示、应用场景、优缺点及适用环境。通过创建外观类,将复杂系统的内部实现细节隐藏起来,只暴露出简化的接口给客户端,从而降低耦合度,提高系统的可维护性和可扩展性。
1.1 外观模式由来
外观模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,外观模式被引入。
门面模式原理和实现都特别简单,应用场景也比较明确,主要在接口设计方面使用。更多内容
1.2 外观模式定义
门面模式,也叫外观模式,英文全称是 Facade Design Pattern。
在 GoF 的《设计模式》一书中,门面模式是这样定义的:Provide a unified interface to a set of interfaces in a subsystem. Facade Pattern defines a higher-level interface that makes the subsystem easier to use.
翻译成中文就是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。
外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
1.3 外观模式场景
应用场景:
- 医院接待:医院的接待人员简化了挂号、门诊、划价、取药等复杂流程。
- Java三层架构:通过外观模式,可以简化对表示层、业务逻辑层和数据访问层的访问。
1.4 外观模式思考
外观模式的核心思想主要是通过创建一个外观类,将复杂系统的内部实现细节隐藏起来,只暴露出一个简化的接口给客户端。客户端只需要与外观类进行交互,而不需要直接与子系统的组件进行交互,从而达到想要的效果。
在思考外观模式时,可以考虑以下几个方面:
- 系统的复杂性:外观模式适用于系统的复杂性较高,包含多个子系统或模块的情况。
- 客户端的便利性:外观模式旨在提供一个简化的接口给客户端使用,使得客户端可以更方便地使用系统的功能,而不需要了解系统的内部实现细节。
- 系统的灵活性和可扩展性:外观模式可以提供系统的灵活性和可扩展性。
- 设计的一致性和封装性:外观模式可以提供设计的一致性和封装性。
1.5 解决的问题
主要解决的问题
- 降低客户端与复杂子系统之间的耦合度。
- 简化客户端对复杂系统的操作,隐藏内部实现细节。更多内容
02.外观模式实现
2.1 罗列一个场景
下面通过一个简单的例子来演示。假设有一个电脑系统,包含了多个子系统,如音乐功能、视频功能和联网功能。可以打开或者关闭某功能。
2.2 外观结构
外观模式包含如下角色:
- Facade: 外观角色。提供一个简化的接口,封装了系统的复杂性。外观模式的客户端通过与外观对象交互,而无需直接与系统的各个组件打交道。
- SubSystem:子系统角色。由多个相互关联的类组成,负责系统的具体功能。外观对象通过调用这些子系统来完成客户端的请求。
- Client:客户端。使用外观对象来与系统交互,而不需要了解系统内部的具体实现。
2.3 外观基本实现
实现方式
- 创建外观类:定义一个类(外观),作为客户端与子系统之间的中介。提供Facade接口,抽象出通用方法打开和关闭。
- 封装子系统操作:外观类将复杂的子系统操作封装成简单的方法。三个子系统类(Subsystem):音乐功能、视频功能和联网功能
提供一个简化的接口
public interface Facade {
void open();
void close();
}
创建三个子系统类(Subsystem):音乐功能、视频功能和联网功能。更多内容
public class Music implements Facade{
@Override
public void open() {
System.out.println("加载音乐");
}
@Override
public void stop() {
System.out.println("关闭音乐");
}
}
public class Video implements Facade{
@Override
public void open() {
System.out.println("打开视频");
}
@Override
public void stop() {
System.out.println("关闭视频");
}
}
public class Internet implements Facade{
@Override
public void open() {
System.out.println("连接网络");
}
@Override
public void stop() {
System.out.println("断开网络");
}
}
创建外观类(Facade) - 电脑系统
public class Computer {
private Music music;
private Video video;
private Internet internet;
public Computer() {
this.music = new Music();
this.video = new Video();
this.internet = new Internet();
}
public void openVideo() {
internet.open();
music.open();
video.open();
}
public void stopVideo() {
video.stop();
music.stop();
internet.stop();
}
}
创建客户端(Client)
private void test() {
Computer computer = new Computer();
System.out.println("播放视频步骤:");
// 播放视频
computer.openVideo();
System.out.println("关闭视频步骤:");
// 关闭视频
computer.stopVideo();
}
在上述例子中,音乐功能、视频功能和联网功能是子系统,Computer是外观类,封装了对这些子系统的调用,并提供了简化的接口给客户端。
在客户端中,我们使用外观模式简化了电脑系统的使用。通过调用外观类的方法,客户端无需直接与多个子系统交互,而是通过外观类来管理对子系统的调用。直接一个接口调用打开视频,打开音乐,连接网络功能
该案例中思考:如果不使用外观模式,客户端通常需要和子系统内部的多个模块交互,也就是说客户端会和这些模块之间都有依赖关系,任意一个模块的变动都可能会引起客户端的变动。
使用外观模式后,客户端只需要和外观类交互,即只和这个外观类有依赖关系,不需要再去关心子系统内部模块的变动情况了。更多内容,这样一来,客户端不但简单,而且这个系统会更有弹性。
2.4 有哪些注意点
外观模式并不是为了解决系统的性能问题,而是为了提供一个简化的接口和封装系统的复杂性。在使用外观模式时,需要权衡封装的程度和灵活性,并根据具体的需求和情况做出决策。
2.5 设计思想
比如该案例中:
- 针对音乐,视频,联网抽象出通用功能,定义成接口【打开和关闭】。充分体现出面向对象中抽象的设计思想!
- 针对音乐,视频,联网各个子系统之间的交互,将他们的逻辑封装到外观类中,充分体现出封装的原则!
外观模式的设计思想是基于封装和抽象的原则,通过将子系统的复杂性隐藏起来,提供一个简化的接口给客户端使用。这样可以提高系统的可维护性、可扩展性和可重用性,同时也使得客户端代码更加简洁和易于理解。
03.外观实例演示
3.1 需求分析
有个需求:我们知道在UI开发中,可以绘制很多图像。比如可以绘制圆形,绘制矩形,绘制椭圆形,绘制……来达到绘制显示的效果。
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。更多内容
3.2 代码案例实现
创建一个接口。
public interface Shape {
void draw();
}
创建实现接口的实体类。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
创建一个外观类。
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
使用该外观类画出各种类型的形状。
private void test() {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
3.3 是否可以优化
比如,现在增加一个需求,绘制各种素材,不管是圆形,矩形,或者椭圆等,都需要创建画笔和画板,可以给绘制设置不同的颜色。如果是你,该如何设计!更多内容
05.外观模式分析
5.1 外观模式优点
- 简化接口:外观模式为子系统提供了一个简化的接口,使得调用者无需关心子系统的内部细节和复杂性,降低了系统的学习成本和使用难度。
- 降低耦合度:通过引入外观类,子系统与调用者之间的耦合度得到了降低。外观类作为中间层,屏蔽了子系统的具体实现,使得子系统内部的修改不会影响到调用者。
- 提高灵活性:由于外观类提供了统一的接口,调用者可以更加灵活地使用子系统,而无需关心子系统的具体实现细节。这有助于增加系统的可扩展性和可维护性。
- 易于维护:当子系统内部发生变更时,只需要修改外观类即可,而无需修改所有调用者的代码。这大大降低了系统的维护成本。
5.2 外观模式缺点
- 可能违背开闭原则:当需要添加新的子系统功能时,可能需要修改外观类或者增加新的外观类。这在一定程度上违背了开闭原则(即对扩展开放,对修改封闭),可能导致系统的稳定性和可维护性受到影响。
- 可能增加不必要的复杂性:在某些情况下,如果子系统本身就很简单或者调用者需要直接访问子系统的某些功能,引入外观模式可能会增加不必要的复杂性。
5.3 适用环境
在以下情况下可以使用外观模式:
- 当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
5.4 模式拓展
不要试图通过外观类为子系统增加新行为
不要通过继承一个外观类在子系统中加入新的行为,这种做法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增加应该通过修改原有子系统类或增加新的子系统类来实现,不能通过外观类来实现。
外观模式与迪米特法则
外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协作伙伴的数量减到最少,使得客户端与子系统内部的对象的相互作用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,降低了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器。
抽象外观类的引入
外观模式最大的缺点在于违背了“开闭原则”,当增加新的子系统或者移除子系统时需要修改外观类,可以通过引入抽象外观类在一定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增加一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时通过修改配置文件来达到不修改源代码并更换外观类的目的。
06.外观代理总结
6.1 总结一下学习
01.外观模式基础
外观模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,外观模式被引入。
定义是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。更多内容
主要解决的问题
- 降低客户端与复杂子系统之间的耦合度。
- 简化客户端对复杂系统的操作,隐藏内部实现细节。
02.外观模式实现
假设有一个电脑系统,包含了多个子系统,如音乐功能、视频功能和联网功能。可以打开或者关闭某功能。
实现方式
- 创建外观类:定义一个类(外观),作为客户端与子系统之间的中介。提供Facade接口,抽象出通用方法打开和关闭。
- 封装子系统操作:外观类将复杂的子系统操作封装成简单的方法。三个子系统类(Subsystem):音乐功能、视频功能和联网功能
比如该案例中:
- 针对音乐,视频,联网抽象出通用功能,定义成接口【打开和关闭】。充分体现出面向对象中抽象的设计思想!
- 针对音乐,视频,联网各个子系统之间的交互,将他们的逻辑封装到外观类中,充分体现出封装的原则!
03.外观实例演示
有个需求:我们知道在UI开发中,可以绘制很多图像。比如可以绘制圆形,绘制矩形,绘制椭圆形,绘制……来达到绘制显示的效果。更多内容
05.外观模式分析
外观模式优点:1.简化接口;2.降低耦合;3.提高灵活性;4.方便维护
外观模式缺点:1.当添加新的子类系统,可能需要修改外观类,或者破坏开闭原则;
使用建议:建议1不要通过外观类给子类系统加入新的行为。
6.2 更多内容推荐
模块 | 描述 | 备注 |
---|---|---|
GitHub | 多个YC系列开源项目,包含Android组件库,以及多个案例 | GitHub |
博客汇总 | 汇聚Java,Android,C/C++,网络协议,算法,编程总结等 | YCBlogs |
设计模式 | 六大设计原则,23种设计模式,设计模式案例,面向对象思想 | 设计模式 |
Java进阶 | 数据设计和原理,面向对象核心思想,IO,异常,线程和并发,JVM | Java高级 |
网络协议 | 网络实际案例,网络原理和分层,Https,网络请求,故障排查 | 网络协议 |
计算机原理 | 计算机组成结构,框架,存储器,CPU设计,内存设计,指令编程原理,异常处理机制,IO操作和原理 | 计算机基础 |
学习C编程 | C语言入门级别系统全面的学习教程,学习三到四个综合案例 | C编程 |
C++编程 | C++语言入门级别系统全面的教学教程,并发编程,核心原理 | C++编程 |
算法实践 | 专栏,数组,链表,栈,队列,树,哈希,递归,查找,排序等 | Leetcode |
Android | 基础入门,开源库解读,性能优化,Framework,方案设计 | Android |
23种设计模式
23种设计模式 & 描述 & 核心作用 | 包括 |
---|---|
创建型模式 提供创建对象用例。能够将软件模块中对象的创建和对象的使用分离 | 工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 单例模式(Singleton Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern) |
结构型模式 关注类和对象的组合。描述如何将类或者对象结合在一起形成更大的结构 | 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) |
行为型模式 特别关注对象之间的通信。主要解决的就是“类或对象之间的交互”问题 | 责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式(Iterator Pattern) 中介者模式(Mediator Pattern) 备忘录模式(Memento Pattern) 观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern) |
6.3 更多内容
- GitHub:https://github.com/yangchong211
- 我的编程网站:https://yccoding.com
- 博客汇总:https://github.com/yangchong211/YCBlogs
- 设计模式专栏:https://github.com/yangchong211/YCDesignBlog
- Java高级进阶专栏:https://github.com/yangchong211/YCJavaBlog
- 网络协议专栏:https://github.com/yangchong211/YCNetwork
- 计算机基础原理专栏:https://github.com/yangchong211/YCComputerBlog