首页 > 其他分享 >门面模式

门面模式

时间:2022-11-07 18:24:47浏览次数:75  
标签:void 接口 模式 门面 com public

复习引入

一、几种设计模式

(1)创建型:工厂模式(简单工厂、抽象工厂)、单例模式、原型模式、建造者模式。

​ 随着软件内部分工原来月明确,对象的创建和对象的使用分开也就成为了必然趋势。因为对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。

(2)结构型:装饰器模式、适配器模式、组合模式、代理模式、享元模式、桥接模式、外观模式。

​ 在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。

(3)行为型:观察者模式、模板模式、策略模式、迭代器模式、备忘录模式、命令模式、解释器模式、中介模式、职责链模式。

​ 在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高。

二、适配器模式( Adapter Design Pattern)

(1)适配器模式解决什么问题?

​ 适配器是做接口转换,解决的是原接口和目标接口不匹配的问题。

(2)适配器模式回忆

​ 顾名思义,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。

​ EG: USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。

​ 实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。

(3)适配器模式的应用场景

​ 封装有缺陷的接口设计、统一多个类的接口设计、替换依赖的外部系统、兼容老版本接口、适配不同格式的数据

三、接口隔离原则、迪米特法则(最小知识原则)、开闭原则、依赖倒转原则

外观模式/门面模式(Facade Design Pattern)

一、为什么要提出门面模式

​ 来解决接口的可复用性(通用性)和易用性之间的矛盾。

​ 为了保证接口的可复用性(或者叫通用性),我们需要将接口尽量设计得细粒度一点,职责 单一一点。但是,如果接口的粒度过小,在接口的使用者开发一个业务功能时,就会导致需 要调用 n 多细粒度的接口才能完成。调用者肯定会抱怨接口不好用。相反,如果接口粒度设计得太大,一个接口返回 n 多数据,要做 n 多事情,就会导致接口不够通用、可复用性不好。接口不可复用,那针对不同的调用者的业务需求,我们就需要开发不同的接口来满足,这就会导致系统的接口无限膨胀。

​ 粒度:粒度就是同一维度下,数据统计的粗细程度,计算机领域中粒度指系统内存扩展增量的最小值。粒度问题是设计数据仓库的一个最重要方面。粒度是指数据仓库的数据单位中保存数据的细化或综合程度的级别。细化程度越高,粒度级就越小;相反,细化程度越低,粒度级就越大。数据的粒度一直是一个设计问题。

​ “粗粒度和细粒度的区别主要是出于重用的目的,像类的设计:为尽可能重用,所以采用细粒度的设计模式,将一个复杂的类(粗粒度)拆分成高度重用的职责清晰的类(细粒度)。对于数据库的设计:原责:尽量减少表的数量与表与表之间的连接,能够设计成一个表的情况就不需要细分,所以可考虑使用粗粒度的设计方式。”

//一下那个TaskService是粗粒度的,哪个是细粒度的?
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;
interface TaskService{
  public List getTaskById(int id);
  public List getTaskByName(String name);
  public List getTaskByAge(int age);
}

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;
interface TaskService{
  public List getTask(Person person);
}

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;
@Data
public class Person {
    private String name;
    private String gender;
    private int age;
}

二、门面模式的定义

​ 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. 翻译成中文就是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。(下图为门面模式的UML类图)

image-20221106110659894

​ 解释:假设有一个系统 A,提供了 a、b、c、d 四个接口。系统 B 完成某个业务功能,需要调用 A 系统的 a、b、d 接口。利用门面模式,我们提供一个包裹 a、b、d 接口调用的门面接口 x,给系统 B 直接使用。

​ 代码示例:其中Facade是外观角色,也叫门面角色,客户端可以调用这个角色的方法,此角色知晓子系统的所有功能和责任,将客户端的请求代理给适当的子系统对象;Subsystem是子系统角色,可以同时拥有一个或多个子系统,每一个子系统都不是一个单独的类,而是一个类的集合,子系统并不知道门面的存在。

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class Facade {
    //被委托的对象
    SubSystemA a;
    SubSystemB b;
    SubSystemC c;
    SubSystemD d;

    public Facade() {
        a = new SubSystemA();
        b = new SubSystemB();
        c = new SubSystemC();
        d = new SubSystemD();
    }

    //提供给外部访问的方法
    public void methodA() {
        this.a.dosomethingA();
    }

    public void methodB() {
        this.b.dosomethingB();
    }

    public void methodC() {
        this.c.dosomethingC();
    }

    public void methodD() {
        this.d.dosomethingD();
    }
}

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class SubSystemA {
    public void dosomethingA() {
        System.out.println("子系统方法A");
    }
}
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class SubSystemB {
    public void dosomethingB() {
        System.out.println("子系统方法B");
    }
}

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class SubSystemC {
    public void dosomethingC() {
        System.out.println("子系统方法C");
    }
}

/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class SubSystemD {
    public void dosomethingD() {
        System.out.println("子系统方法D");
    }
}


/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test1;

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();

        facade.methodA();
        facade.methodB();
    }
}

运行结果:

image-20221106140454145

三、门面模式的实现

//基金类,基金经理人通过该类作为中间交互者,可以接受投资者的资金,进行购买和赎回操作。
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test2;

public class Fund {
    Stock1 stock1;
    Stock2 stock2;
    Stock3 stock3;

    public Fund() {
        stock1 = new Stock1();
        stock2 = new Stock2();
        stock3 = new Stock3();
    }

    //购买基金
    public void buyFund() {
        stock1.buy();
        stock2.buy();
        stock3.buy();
    }

    //赎回基金
    public void sellFund() {
        stock1.sell();
        stock2.sell();
        stock3.sell();
    }
}

//股票作为示例。内部由买入和卖出两种操作。
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test2;

public class Stock1 {

    //买股票
    public void buy() {
        System.out.println("股票1买入");
    }

    //卖股票
    public void sell() {
        System.out.println("股票1卖出");
    }

}
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test2;

public class Stock2 {

    //买股票
    public void buy() {
        System.out.println("股票2买入");
    }

    //卖股票
    public void sell() {
        System.out.println("股票2卖出");
    }

}
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test2;

public class Stock3 {

    //买股票
    public void buy() {
        System.out.println("股票3买入");
    }

    //卖股票
    public void sell() {
        System.out.println("股票3卖出");
    }

}

//用户通过该类对基金进行购买和赎回操作。
/**
 * date: 2022/11/6
 *
 * @author Arc
 */
package com.qlu.test2;

public class Client {

    public static void main(String[] args) {
        Fund fund = new Fund();

        //基金购买
        fund.buyFund();
        System.out.println("-------------");
        //基金赎回
        fund.sellFund();
    }

}

​ 我们只需在客户端购买和赎回即可,内部的任何操作都不需要我们关注,对于面向对象有一定基础的朋友,即使没有听说过外观模式,也完全有可能在很多时候使用它,因为它完美地体现了依赖倒转原则和迪米特法则的思想,所以是非常常用的模式之一。

运行结果:

image-20221107180959777

四、应用场景 ——门面模式让子系统更加易用

1、解决易用性问题

门面模式可以用来封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。比如,Linux 系统调用函数就可以看作一种“门面”。它是 Linux 操作系统暴露给开发者的一组“特殊”的编程接口,它封装了底层更基础的 Linux 内核调用。再比如, Linux 的 Shell 命令,实际上也可以看作一种门面模式的应用。它继续封装系统调用,提供 更加友好、简单的命令,让我们可以直接通过执行命令来跟操作系统交互。

接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该强迫依赖它不需要的接口。

2、解决性能问题

​ 通过将多个接口调用替换为一个门面接口调用,减少网络通信成本,提高 App 客户端的响应速度。

​ EG:系统 A 是一个后端服务器,系统 B 是 App 客户端。App 客户端通过后端服务器提供的接口来获取数据。我们知道,App 和服务器之间是通过移动网络通信 的,网络通信耗时比较多,为了提高 App 的响应速度,我们要尽量减少 App 与服务器之 间的网络通信次数。 假设,完成某个业务功能(比如显示某个页面信息)需要“依次”调用 a、b、d 三个接 口,因自身业务的特点,不支持并发调用这三个接口。 如果我们现在发现 App 客户端的响应速度比较慢,排查之后发现,是因为过多的接口调用 过多的网络通信。针对这种情况,我们就可以利用门面模式,让后端服务器提供一个包裹 a、b、d 三个接口调用的接口 x。App 客户端调用一次接口 x,来获取到所有想要的数 据,将网络通信的次数从 3 次减少到 1 次,也就提高了 App 的响应速度。

​ 从代码实现的角度来看,该如何组织门面接口和非门面接口? (可以过,因为我没有开发经验)

​ A:如果门面接口不多,我们完全可以将它跟非门面接口放到一块,也不需要特殊标记,当作普通接口来用即可。如果门面接口很多,我们可以在已有的接口之上,再重新抽象出一层,专门放置门面接口,从类、包的命名上跟原来的接口层做区分。如果门面接口特别多,并且很多都是跨多个子系统的,我们可以将门面接口放到一个新的子系统中。

3、 解决分布式事务问题

​ 关于利用门面模式来解决分布式事务问题,我们通过一个例子来解释一下。

在一个金融系统中,有两个业务领域模型,用户和钱包。这两个业务领域模型都对外暴露了 一系列接口,比如用户的增删改查接口、钱包的增删改查接口。假设有这样一个业务场景: 在用户注册的时候,我们不仅会创建用户(在数据库 User 表中),还会给用户创建一个钱包(在数据库的 Wallet 表中)。 对于这样一个简单的业务需求,我们可以通过依次调用用户的创建接口和钱包的创建接口来 完成。但是,用户注册需要支持事务,也就是说,创建用户和钱包的两个操作,要么都成 功,要么都失败,不能一个成功、一个失败。 要支持两个接口调用在一个事务中执行,是比较难实现的,这涉及分布式事务问题。虽然我 们可以通过引入分布式事务框架或者事后补偿的机制来解决,但代码实现都比较复杂。而最 简单的解决方案是,利用数据库事务或者 Spring 框架提供的事务(如果是 Java 语言的 话),在一个事务中,执行创建用户和创建钱包这两个 SQL 操作。这就要求两个 SQL 操作 要在一个接口中完成,所以,我们可以借鉴门面模式的思想,再设计一个包裹这两个操作的 新接口,让新接口在一个事务中执行两个 SQL 操作。

课上思考

一、适配器模式和门面模式的共同点是,将不好用的接口适配成好用的接口。你可以试着总 结一下它们的共同点和区别吗?

​ A1:适配器是做接口转换,解决的是原接口和目标接口不匹配的问题。 门面模式做接口整合,解决的是多接口调用带来的问题。适配器模式与门面模式的共同点都需要二次封装,隐藏内部细节。不同点为适配器是为 了统一格式,门面是为了简单易用。

二、门面模式的优缺点

​ 优点:减少了系统的相互依赖;提高灵活性,不管系统内部如何变化,只要不影响外观对象,可以自由活动;提高了安全性,想让你访问那些业务就开通哪些逻辑,不在外观上开通的方法就访问不到。

​ 缺点:不符合开闭原则,修改麻烦。

三、外观模式体现了哪些设计原则

​ 迪米特法则、接口隔离原则、依赖倒转原则

参考: https://www.cnblogs.com/ajunForNet/p/3492101.html

https://www.cnblogs.com/adamjwh/p/9048594.html

https://www.cnblogs.com/HoneyTYX/p/9396446.html

https://baike.baidu.com/item/粒度/13014724?fr=aladdin

标签:void,接口,模式,门面,com,public
From: https://www.cnblogs.com/purearc/p/16866936.html

相关文章

  • 策略者模式
    策略者模式: 定义了算法组,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用的算法客户! 案例解析:  游戏中的不同的角色可以使用不同的武器来进行......
  • 创建型设计模式-原型模式(深拷贝,浅拷贝)
    Person类:publicclassPerson{publicstringName{get;set;}publicintAge{get;set;}publicAddressAddress{get;set;......
  • 创建型设计模式-单例模式(为什么要双重加锁判断)
    代码publicclassSingleObject{privatestaticSingleObjectinstance;privatestaticobjectlockobj=newobject();privateSingleObject(){}publicstatic......
  • 设计模式学习(二):单例模式
    设计模式学习(二):单例模式作者:Grey原文地址:博客园:设计模式学习(二):单例模式CSDN:设计模式学习(二):单例模式单例模式单例模式是创建型模式。单例的定义:“一个类只允许创建......
  • 〖JAVA养成计划〗设计模式-单例设计模式以及衍生的多例设计模式
     单例设计模式packagecom.tongbu;/***单例设计模式分为两类:*①是俄汉式*②是懒汉式*以下程序是俄汉式:不管程序中有没有使用,都实例化对象。*@authorAdministrat......
  • sshd开启调试模式
    今天使用私钥方式无法登录服务器,做了以下排查,都没解决问题:1.删除root目录下.ssh目录,重新解压自己秘钥2.查看.ssh目录及子文件权限3.替换正常的sshd_config文件只能尝试......
  • 门面模式
    复习引入一、几种设计模式(1)创建型:工厂模式(简单工厂、抽象工厂)、单例模式、原型模式、建造者模式。​ 随着软件内部分工原来月明确,对象的创建和对象的使用分开也就成为......
  • 23种设计模式之自定义Spring框架(五)
    7,自定义Spring框架7.1spring使用回顾自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟。数据访问层。定义UserDao接口及其子......
  • 23种设计模式之设计模式介绍(一)
    1,设计模式概述1.1软件设计模式的产生背景"设计模式"最初并不是出现在软件设计中,而是被用于建筑领域的设计中。1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境......
  • 设计模式
    设计模式(一)——简单工厂设计模式(二)——工厂方法设计模式(三)——抽象工厂设计模式(四)——建造者模式设计模式(五)——原型模式设计模式(六)——单例模式......