首页 > 编程语言 >Java中的外观模式

Java中的外观模式

时间:2024-10-07 19:23:08浏览次数:1  
标签:外观 Java 调用者 destination 模式 public 子系统

Java中的外观模式

综述

本文总结外观模式的定义, 特点, 使用场景并给出了具体的示例.

外观模式的定义

外观模式(门面模式)是一种结构型设计模式. 其主要目的是为复杂系统提供一个简化的接口. 帮助客户端代码与系统的子系统进行交互, 同时还可以省略大量的细节. 这种设计模式可以称得上设计模式中最简单的模式, 甚至可以不加"之一". 因为绝大部分的「封装」操作都可以归类到外观模式当中, 可以说很多新手开发者在没有接触过外观模式的情况下已经在不知不觉间用到了外观模式.

外观模式的角色组成

在外观模式的完整模型中三个角色, 但在一些简化模型中外部调用者被省略掉了

  • 外部调用者: 外部调用者通过外观类调用子系统的功能, 在通常的模型中是隐形的, 但完整的模型中需要有它
  • 外观类: 外观类持有子系统实例, 对调用者隐藏方法的调用细节, 调用者可以通过调用外观类的方法, 调用子系统提供的功能
  • 子系统: 对外提供具体的实现功能, 模式要求至少有一个子系统

外观模式的优缺点

它的优点在于:

  • 提供统一接口: 通过外观类, 将系统的复杂性隐藏起来, 提供了一个简单易用的接口给调用者.
  • 隐藏底层细节: 迪米特法则又称为最少知识原则, 此原则认为, 一个对象应当对其他对象尽可能少的了解. 而外观模式是迪米特法则的最佳实践方式之一, 它降低了调用者和子系统之间的耦合度, 使得调用者不需要了解系统内部的具体实现细节.
  • 解耦调用者和子系统: 外观类提供了一个单一的入口, 有助于提高系统的封装性和安全性.

而缺点则是:

  • 不符合开闭原则: 如果要新增或者修改子系统的功能, 需要修改外观类
  • 不适合大规模系统: 当子系统过于复杂且分散时, 或者子系统之间的交互频繁改变时, 外观模式可能也会随之频繁修改. 使用外观模式可能导致外观类变得庞大且复杂.

外观模式的使用场景

外观模式的使用场景很简单

  1. 当子系统提供了过剩的自定义功能时. 注意, 这里过剩的评价标准是外部调用者用不着. 比如子系统提供对某个参数设置 1 - 100 档位的自定义功能, 但是调用者只需要 1 和 100 总计2个档位, 这就可以称为过剩.
  2. 当调用者用到了某个系统中的多个功能, 但从角色定位来说, 它不是这个系统的一员时. 这时候可以认为这个由多个子系统组成的模块应该有一个统一的接口对外提供服务. 这个统一的接口就是外观类.

所以从以上两点可以看出外观模式和封装的概念非常的相似. 事实上外观模式可以看作封装在设计模式上的拓展实现. 封装是面向对象编程的基础概念, 它可以应用于类/对象等层面, 主要目的是隐藏数据和实现细节, 通过提供公共接口来控制访问. 而外观模式关注的是隔离调用者和子系统.

这里可以用两个生活场景进行比喻说明

旅行社

旅行社通常会将多种服务, 如机票预订、酒店预订、用车服务、导游安排、门票购买等打包成一个统一的旅游套餐, 类似于「西安7天游」「广州1日游」之类的称呼. 这个旅游套餐就像是外观模式的实例, 这里子系统就是这一个个的服务提供者, 而外观类就是旅行社本身. 「西安7天游」「广州1日游」是外观类对外提供的隐藏内部子系统细节的方法, 而购买服务的顾客就是外部调用者.

装修公司

装修公司可能会提供各种家居装修包, 比如简约风格、现代风格或者新中式风格. 每个装修包包括了室内设计、材料选择、施工服务和家具搭配等. 业主可以选择一个装修包来完成整个家居装修, 而不必自行挑选和协调每个装修细节. 这里准备购买装修服务的业主就是外部调用者, 而装修公司就是外观类, 室内设计服务, 材料采购, 联系监工, 施工服务和家具定制/家具采购等都是被隐藏起来的子系统.

当然, 实际应用场景同样非常的多,典型的比如

Junit

JUnit 是一个广泛用于 Java 单元测试的框架. 尽管它的主要功能是帮助开发人员编写和运行单元测试, 但它也是一个很好的外观模式的例子. 通过 JUnit, 开发人员可以简单地编写测试用例和断言, 而无需直接与底层的测试框架或测试运行器交互.

Hibernate

Hibernate 是一个流行的对象关系映射(ORM)框架, 它简化了 Java 对象与数据库表之间的映射关系. 虽然 Hibernate 的主要目的是将对象持久化到数据库中, 但它也隐藏了底层数据库访问和 JDBC 操作的复杂性, 为开发人员提供了一个简单而强大的接口.

外观模式的示例

以之前的旅行社旅游产品为例子

//外观类
public class TravelPackageFacade {
    private FlightBookingService flightBookingService;
    private HotelBookingService hotelBookingService;
    private CarRentalService carRentalService;
    private TourGuideService tourGuideService;
    private TicketPurchaseService ticketPurchaseService;

    public TravelPackageFacade() {
        // 初始化各个子系统服务
        this.flightBookingService = new FlightBookingService();
        this.hotelBookingService = new HotelBookingService();
        this.carRentalService = new CarRentalService();
        this.tourGuideService = new TourGuideService();
        this.ticketPurchaseService = new TicketPurchaseService();
    }

    // 提供一个简化的接口方法,封装整个旅游套餐购买过程
    public void bookTravelPackage(String destination, int duration) {
        System.out.println("购买旅行社的 " + destination + duration + "天游 产品");

        // 简化的购买流程,调用各个子系统服务
        this.flightBookingService.bookFlight(destination, duration);
        this.hotelBookingService.bookHotel(destination, duration);
        this.carRentalService.rentCar(destination);
        this.tourGuideService.arrangeTourGuide(destination);
        this.ticketPurchaseService.purchaseTickets(destination);

        System.out.println("\n" + destination + duration + "天游 产品预定成功");
    }
}
//各个子项目
public class FlightBookingService {
    public void bookFlight(String destination, int duration) {
        System.out.println("预定前往 " + destination + " 的机票及 " + duration + " 后的返程票");
    }
}
public class HotelBookingService {
    public void bookHotel(String destination, int duration) {
        System.out.println("预定 " + destination + " 的酒店 " + duration + " 天");
    }
}
public class CarRentalService {
    public void rentCar(String destination) {
        System.out.println("出租 " + destination + " 当地的旅游专车服务");
    }
}
public class TourGuideService {
    public void arrangeTourGuide(String destination) {
        System.out.println("安排 " + destination + " 当地的导游");
    }
}
public class TicketPurchaseService {
    public void purchaseTickets(String destination) {
        System.out.println("购买 " + destination + " 当地旅游景区套票");
    }
}
//最后是外部调用者
public class Main {
    public static void main(String[] args) {
        var facade = new TravelPackageFacade();
        facade.bookTravelPackage("西安",7);
    }
}

总结

外观模式理解简单应用广泛, 作为封装概念在设计模式上的某种实现, 只要是熟悉面向对象的开发者, 理解起来应该不需要超过半个小时, 甚至可能平时工作时不知不觉就用到了. 唯一的难点可能在于什么时候改用, 什么时候可以不用. 而这一点只能由开发者自己在开发中慢慢体会.

标签:外观,Java,调用者,destination,模式,public,子系统
From: https://www.cnblogs.com/dwcg/p/18326745

相关文章

  • 在C#中使用适配器Adapter模式和扩展方法解决面向的对象设计问题
    之前有阵子在业余时间拓展自己的一个游戏框架,结果在实现的过程中发现一个设计问题。这个游戏框架基于MonoGame实现,在MonoGame中,所有的材质渲染(TextureRendering)都是通过SpriteBatch类来完成的。举个例子,假如希望在屏幕的某个地方显示一个图片材质(imageTexture),就在Game类的子类的D......
  • 视野修炼-技术周刊第104期 | 下一代 JavaScript 工具链
    欢迎来到第104期的【视野修炼-技术周刊】,下面是本期的精选内容简介......
  • Java中的任务超时处理
    Java中的任务超时处理综述任务超时处理是编程世界中一个不可或缺且常见的处理机制,特别是在进行耗时任务时,如网络请求,数据库查询,大规模数据处理等场景。在这些情况下,为了防止任务因各种不可预测的因素(如网络延迟,服务器响应超时,数据量过大等)而无休止地占用宝贵的系......
  • Java中的策略模式
    Java中的策略模式综述本文总结了策略模式的定义,特点,使用场景以及实现思路。策略模式的定义策略模式说通了,就是定义一系列的算法,将它们各自封装起来,并且使用一个共同的接口使它们可相互替换.使得算法和算法之间没有耦合,这样如果方法需要修改或者添加,工程师不需要修......
  • Java基础第八章(多态)
    多态1.方法体现多态方法重载体现多态对象通过传入不同数量的参数,会调用不同的sun方法,体现出多态方法重写体现多态A类和B类是继承关系,通过不同对象调用对应类中重写的方法体现2.对象体现多态编译是javac,运行是java(1)一个对象的编译类型和运行类型可以不一致将父......
  • JavaScript 小知识:轻松搞定 ArrayBuffer 到 Base64 的转换
    关键词:ArrayBuffer,Base64,栈溢出,TextDecoder,btoa,性能优化,JavaScript,兼容性摘要本文探讨了在JavaScript中将ArrayBuffer转换为Base64字符串时遇到的栈溢出问题,并提供了几种实用的解决方案。我们将通过生动的比喻来解释相关概念,比较不同方法的性能和兼......
  • JavaScript 小知识:轻松搞定 ArrayBuffer 到 Base64 的转换
    关键词:ArrayBuffer,Base64,栈溢出,TextDecoder,btoa,性能优化,JavaScript,兼容性摘要本文探讨了在JavaScript中将ArrayBuffer转换为Base64字符串时遇到的栈溢出问题,并提供了几种实用的解决方案。我们将通过生动的比喻来解释相关概念,比较不同方法的性能和兼......
  • JavaScript 小知识:轻松搞定 ArrayBuffer 到 Base64 的转换
    关键词:ArrayBuffer,Base64,栈溢出,TextDecoder,btoa,性能优化,JavaScript,兼容性摘要本文探讨了在JavaScript中将ArrayBuffer转换为Base64字符串时遇到的栈溢出问题,并提供了几种实用的解决方案。我们将通过生动的比喻来解释相关概念,比较不同方法的性能和兼......
  • 基于JAVA的鲜花商城管理系统(源码+定制+讲解)鲜花商城管理系统、鲜花商城管理平台、鲜
    博主介绍:  ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生......
  • Java与线程
    Java与线程1.线程的实现线程是比进程更轻量级的调度执行单位,线程的引人,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件IO等),又可以独立调度。目前线程是Java里面进行处理器资源调度的最基本单位。主流的操作系统都提供了线程实现,Java语言......