设计模式学习笔记 - 外观模式

news2024/11/23 14:51:09

设计模式学习笔记 - 外观模式

  • 一、影院管理问题
  • 二、传统方式解决影院管理问题
  • 三、外观模式介绍
    • 1、基本介绍
    • 2、原理类图
  • 四、外观模式解决影院管理问题
  • 五、外观模式在MyBatis框架应用的源码分析
  • 六、外观模式的注意事项和细节

一、影院管理问题


组建一个家庭影院:DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机。要求完成使用家庭影院的功能,其过程为直接用遥控器统筹各设备开关:

1.打开爆米花机
2.放下屏幕
3.打开投影仪
4.打开音响
5.打开DVD,选dvd
6.去拿爆米花
7.调暗灯光
8.播放dvd
9.观影结束后,关闭各种设备

二、传统方式解决影院管理问题

  • 类图:
    在这里插入图片描述

  • 传统方式解决影院管理问题分析:
    (1)在 Client的main方法中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程。在Client中不利于去维护对子系统的操作。
    (2)解决思路:定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口中提供四个方法on、play、pause、off),用来访问子系统中的一群接口。也就是说,通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个一致的接口发生调用,而无需关心这个子系统的内部细节。这就是使用了外观模式。

三、外观模式介绍

1、基本介绍


外观模式(Facade Pattern),也叫“过程模式”。外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节。

外观模式可以理解为转换一群接口,客户只要调用一个接口,而不用调用多个接口才能达到目的。

外观模式就是解决多个复杂接口带来的使用困难,起到简化用户操作的作用。

2、原理类图


在这里插入图片描述

说明:

  • 外观类(Facade):为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象。
  • 子系统的集合:指模块或者子系统,处理Facade对象指派的任务,是功能实际提供者。
  • 调用者(Client):外观接口的调用者。

四、外观模式解决影院管理问题

  • 类图:
    在这里插入图片描述

  • 实现代码:

package com.etc.design.facade;

public class Client {
	public static void main(String[] args) {
		// 使用外观类实现过程
		HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
		// 开启所有设备
		homeTheaterFacade.ready();
		// DVD播放
		homeTheaterFacade.play();
		// DVD暂停
		homeTheaterFacade.pause();
		// 关闭所有设备
		homeTheaterFacade.end();
	}
}
package com.etc.design.facade;

/**
 * 外观类
 */
public class HomeTheaterFacade {
	//定义各个子系统对象
	private TheaterLight theaterLight;
	private Popcorn popcorn;
	private Stereo stereo;
	private Projector projector;
	private Screen screen;
	private DVDPlayer dVDPlayer;

	//构造器
	public HomeTheaterFacade() {
		super();
		this.theaterLight = TheaterLight.getInstance();
		this.popcorn = Popcorn.getInstance();
		this.stereo = Stereo.getInstance();
		this.projector = Projector.getInstance();
		this.screen = Screen.getInstance();
		this.dVDPlayer = DVDPlayer.getInstanc();
	}

	// 操作分成4步
	public void ready() {
		System.out.println("-----开启所有设备-----");
		popcorn.on();
		popcorn.pop();
		screen.down();
		projector.on();
		stereo.on();
		dVDPlayer.on();
		theaterLight.dim();
	}

	public void play() {
		System.out.println("-----播放DVD-----");
		dVDPlayer.play();
	}

	public void pause() {
		System.out.println("-----暂停DVD-----");
		dVDPlayer.pause();
	}

	public void end() {
		System.out.println("-----关闭所有设备-----");
		popcorn.off();
		theaterLight.bright();
		screen.up();
		projector.off();
		stereo.off();
		dVDPlayer.off();
	}
}
package com.etc.design.facade;

public class DVDPlayer {
	// 使用用饿汉单例模式
	private static DVDPlayer instance = new DVDPlayer();
	
	public static DVDPlayer getInstanc() {
		return instance;
	}
	
	public void on() {
		System.out.println(" DVD on ");
	}

	public void off() {
		System.out.println(" DVD off ");
	}
	
	public void play() {
		System.out.println(" DVD play ");
	}

	public void pause() {
		System.out.println(" DVD pause ");
	}
}
package com.etc.design.facade;

public class Popcorn {
	// 使用用饿汉单例模式
	private static Popcorn instance = new Popcorn();
	
	public static Popcorn getInstance() {
		return instance;
	}
	
	public void on() {
		System.out.println(" popcorn on ");
	}
	
	public void off() {
		System.out.println(" popcorn ff ");
	}
	
	public void pop() {
		System.out.println(" popcorn is poping  ");
	}
}
package com.etc.design.facade;

public class Projector {
	// 使用用饿汉单例模式
	private static Projector instance = new Projector();
	
	public static Projector getInstance() {
		return instance;
	}
	
	public void on() {
		System.out.println(" Projector on ");
	}
	
	public void off() {
		System.out.println(" Projector ff ");
	}
	
	public void focus() {
		System.out.println(" Projector is Projector  ");
	}
}
package com.etc.design.facade;

public class Screen {
	// 使用用饿汉单例模式
	private static Screen instance = new Screen();
	
	public static Screen getInstance() {
		return instance;
	}
	
	public void up() {
		System.out.println(" Screen up ");
	}
	
	public void down() {
		System.out.println(" Screen down ");
	}
}
package com.etc.design.facade;

public class Stereo {
	// 使用用饿汉单例模式
	private static Stereo instance = new Stereo();
	
	public static Stereo getInstance() {
		return instance;
	}
	
	public void on() {
		System.out.println(" Stereo on ");
	}
	
	public void off() {
		System.out.println(" Stereo off ");
	}
	
	public void up() {
		System.out.println(" Stereo up ");
	}

	public void down() {
		System.out.println(" Stereo down ");
	}
}
package com.etc.design.facade;

public class TheaterLight {
	// 使用用饿汉单例模式
	private static TheaterLight instance = new TheaterLight();

	public static TheaterLight getInstance() {
		return instance;
	}

	public void on() {
		System.out.println(" TheaterLight on ");
	}

	public void off() {
		System.out.println(" TheaterLight off ");
	}

	public void dim() {
		System.out.println(" TheaterLight dim ");
	}

	public void bright() {
		System.out.println(" TheaterLight bright ");
	}
}

在这里插入图片描述

五、外观模式在MyBatis框架应用的源码分析


MyBatis中的Configuration去创建MetaObject对象使用到外观模式。

  • 类图:

  • 源码:
package org.apache.ibatis.session;
......
public class Configuration {
    ......
	protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
   	protected ObjectFactory objectFactory = new DefaultObjectFactory();
    protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
    ......
    public MetaObject newMetaObject(Object object) {
    	return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
	}
    ......
}
package org.apache.ibatis.reflection;
......
public class MetaObject {
	private Object originalObject;
	private ObjectWrapper objectWrapper;
	private ObjectFactory objectFactory;
	private ObjectWrapperFactory objectWrapperFactory;
	private ReflectorFactory reflectorFactory;

	private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
		this.originalObject = object;
		this.objectFactory = objectFactory;
		this.objectWrapperFactory = objectWrapperFactory;
		this.reflectorFactory = reflectorFactory;
        if (object instanceof ObjectWrapper) {
          	this.objectWrapper = (ObjectWrapper) object;
        } else if (objectWrapperFactory.hasWrapperFor(object)) {
          	this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
        } else if (object instanceof Map) {
          	this.objectWrapper = new MapWrapper(this, (Map) object);
        } else if (object instanceof Collection) {
          	this.objectWrapper = new CollectionWrapper(this, (Collection) object);
        } else {
          	this.objectWrapper = new BeanWrapper(this, object);
		}
	}
  	......
  	public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    	if (object == null) {
      		return SystemMetaObject.NULL_META_OBJECT;
    	} else {
      		return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    	}
  	}
  	......
}
package org.apache.ibatis.reflection.factory;

public interface ObjectFactory {
	......
}
package org.apache.ibatis.reflection.factory;

public class DefaultObjectFactory implements ObjectFactory, Serializable {
	......
}
package org.apache.ibatis.reflection.wrapper;

public interface ObjectWrapperFactory {
	......
}
package org.apache.ibatis.reflection.wrapper;

public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
	......
}

六、外观模式的注意事项和细节


(1)外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性。
(2)外观模式对客户端与子系统的耦合关系进行解耦,让子系统内部的模块更易维护和扩展。
(3)通过合理的使用外观模式,可以更好的划分访问的层次。
(4)当系统需要进行分层设计时,可以考虑使用外观模式。
(5)在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口,让新系统与Facade类交互,提高复用性。
(6)不能过多的或者不合理的使用外观模式。如果子系统模块过于复杂,可以使用外观模式进行分层。如果子系统模块比较简单,可以直接调用模块。要以让系统有层次,利于维护为目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/366389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ur3+robotiq ft sensor+robotiq 2f 140+realsense d435i配置rviz,gazebo仿真环境

ur3robotiq ft sensorrobotiq 2f 140realsense d435i配置rviz,gazebo仿真环境 搭建环境: ubuntu: 20.04 ros: Nonetic sensor: robotiq_ft300 gripper: robotiq_2f_140_gripper UR: UR3 reasense: D435i 通过下面几篇博客配置好了ur3、力传…

带你轻松实现通讯录(C语言版)

文章目录前言通讯录初始化通讯录运行的基本框架和菜单增添联系人删除联系人查找联系人修改联系人信息展示通讯录通讯录联系人个数排序通讯录文件操作储存通讯录信息销毁通讯录整体代码Contacts.hContacts.ctest.c写在最后前言 学习C语言的小伙伴,相信都要经历实现通…

Web网页测试全流程解析论Web自动化测试

1、功能测试 web网页测试中的功能测试,主要测试网页中的所有链接、数据库连接、用于在网页中提交或获取用户信息的表单、Cookie 测试等。 (1)查看所有链接: 测试从所有页面到被测特定域的传出链接。 测试所有内部链接。 测试链…

开学准备哪些电容笔?ipad触控笔推荐平价

在现代,数码产品的发展受到高技术的驱动。不管是在工作上,还是在学习上,大的显示屏可以使图像更加清晰。Ipad将成为我们日常生活中不可或缺的一部分,无论现在或将来。如果ipad配上一款方便操作的电容笔,将极大地提高我…

Unity性能优化:如何优化Drawcall

前言 降低游戏的Drawcall,是渲染优化很重要的手段,接下来从以下4个方面来分析如何降低DrawCall: 对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀 降低Drawcall的意义是什么?如何查看游戏的Drawca…

C++继承、构造函数和析构函数

构造函数 与 析构函数 构造函数代表一个对象的生成,主要作用是初始化类的成员变量,可以被重载 如果没有显式构造函数,则实例化对象时,系统会自动生成一个无参的构造函数 构造函数的名称与类名相同 析构函数代表的是一个对象的销…

初识Python——“Python”

各位CSDN的uu们你们好呀,今天进入到了我们的新专栏噢,Python是小雅兰的专业课,那么现在,就让我们进入Python的世界吧 计算机基础概念 什么是计算机? 什么是编程? 编程语言有哪些? Python背景知…

MySQL的安装(详解)

文章目录前言一、yum方式安装1、下载并安装MySQL2、 启动MySQL数据库3、查看MySQL初始密码4、登录数据库5、修改MySQL默认密码6、授予root用户远程管理权限7、输入exit退出数据库二、rpm安装方式1、检查2、卸载mariadb3、安装4、启动5、密码总结前言 本教程为Linux下安装mysql的…

若依配置教程(九)若依前后端分离版部署到服务器Nginx(Windows版)

搭建若依环境 要部署到服务器上,首先要在本地运行若依系统 文章目录搭建若依环境后端部署1.在application.yml中修改后台端口,这里默认是8080。2.在application-druid.yml中修改正式环境数据库。3.后端打包部署前端部署下载安装NginxNginx代理配置启动N…

UnityEditor编辑器扩展代码实现Project搜索的实现功能和切换Component等

反射实现切换Gameobjecect-Comp之前介绍过Kinematic Character Controller这个插件这个插件很容易和另外一个插件混淆,两个作者头像比较相像,而且这个插件的作者不太喜欢露脸(他现在做Dot-CharacterControl去了),几乎网…

人人能读懂redux原理剖析

一、Redux是什么? 众所周知,Redux最早运用于React框架中,是一个全局状态管理器。Redux解决了在开发过程中数据无限层层传递而引发的一系列问题,因此我们有必要来了解一下Redux到底是如何实现的? 二、Redux的核心思想…

计算机网络之IP协议(详解

网络层主管地址管理与路由选择。而IP协议就是网络层中一个非常重要的协议。它的作用就是在复杂的网络环境中确定一个合适的路径。IP协议头格式4位版本号(version) 指定IP协议的版本,目前只有两个版本:IP v4和IP v6.对于IP v4来说,这个值就是4…

边缘云是什么?

涂鸦边缘云服务 旨在解决物联网边缘位置的连接需求和提高设备自主管理能力。并与涂鸦 IoT 云服务和 IoT 终端形成云边端三位一体的端到端产品架构。使用涂鸦边缘云,能极大降低设备响应延时、降低网络带宽压力、提高算力分发能力,并构建以下技术优势&…

IDEA 30 个好用天花板技巧,敲代码直接接爽到飞。

IDEA 作为Java开发工具的后起之秀,几乎以碾压之势把其他对手甩在了身后,主要原因还是归功于:好用;虽然有点重,但依旧瑕不掩瑜,内置了非常多的功能,大大提高了日常的开发效率,下面汇总…

LAMP架构与搭建论坛

目录 1、LAMP架构简述 2、各组件作用 3、构建LAMP平台 1.编译安装Apache httpd服务 2.编译安装mysql 3.编译安装php 4.搭建一个论坛 1、LAMP架构简述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整台系统和相关软件,能够提供动…

Spring Boot整合Thymeleaf和FreeMarker模板

虽然目前市场上多数的开发模式采用前后端分离的技术,视图层的技术在小一些的项目中还是非常有用的,所以一直也占有一席之地,如spring官方的spring.io等网站就是使用视图层技术实现的。 目前Spring Boot支持的较好的两个视图层模板引擎是Thyme…

【git】git版本控制

目录 1.在合适的位置打开bush,创建仓库 2.检查:跳转到当前文件夹,显示当前文件夹的相对路径 3.初始化 4.创建一个文本文件readme.txt 5.手动向readme文件中添加一些内容 6.把文件添加到暂存区 7.把文件提交到git仓库 8.手动修改readme.txt文件 9.查看当前…

前端监控之用户行为监控实践2(数据统计mongodb)

一、技术栈介绍 我们当前的项目,后端是node 搭建,数据库是非关系型数据库 mongodb。 二、数据情况介绍 日志存储存储格式如下: 主要包括: key意义type当前访问类型actionTime访问时间content访问内容erp、fullname、orgname、…

【Spring MVC】这一篇,带你从入门到进阶

目录 1、什么是MVC? 2、什么是 Spring MVC 3、如何学好 Spring MVC? 3.1、如何创建 Spring MVC 项目 3.1.1、使用Spring Initializr创建(推荐) 3.2、将 Spring 程序与用户(浏览器)联通 3.3、基础注解…

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口? 6.5 拓展&#…