一文彻底搞明白外观模式

开发 前端
对于一个系统来讲,对外暴露清晰简洁的接口是非常有必要的。这不仅可以节省与调用方的沟通成本,也可以与调用方相对解耦,以便后续独立进行演进。

本篇讲解Java设计模式中的外观模式,分为定义、模式应用前案例、结构、模式应用后案例、适用场景、模式可能存在的困惑和本质探讨7个部分。

定义

外观模式是为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

在新的分类方式中,外观模式被划分至类之间的交互类别中,其简化的是一个类与一组类之间的交互耦合问题。

模式应用前案例

在外观模式中,列举一个电商领域的案例。先来看一下未使用外观模式前的代码实现。

电商领域通常包括库存子系统、支付子系统和物流子系统,代码如下。

public class InventorySystem {//库存子系统


    public void updateInventory(String product, int quantity) {
        System.out.println("Updating inventory for " + product + ": " + quantity);
    }

}

public class PaymentSystem {//支付子系统

    public void processPayment(double amount) {
        System.out.println("Processing payment: $" + amount);
    }

}

public class ShippingSystem {//物流子系统

    public void shipOrder(String address) {
        System.out.println("Shipping order to address: " + address);
    }

}

调用方代码如下。

public class Client {//调用方代码

    public static void main(String[] args) {

        InventorySystem inventory = new InventorySystem();
        PaymentSystem payment = new PaymentSystem();
        ShippingSystem shipping = new ShippingSystem();


        inventory.updateInventory("Computer", 1);
        payment.processPayment(1500);
        shipping.shipOrder("123 Main Street");

    }

}

在上述代码中,不难发现,调用方与各个子系统直接耦合,这样主要带来两个问题。

一个问题是调用方需要知晓每一个子系统的细节。在某些情况下,这些子系统之间的关系也需要知晓。

另一个问题是如果子系统代码发生变更,调用方代码也需要受到关联影响。

结构

外观模式的示例代码如下。

public class SubSystemOne {
    public void MethodOne() {
        System.out.println("Called SubSystemComponentOne's methodOne()");
    }
}

public class SubSystemTwo {
    public void MethodTwo() {
        System.out.println("Called SubSystemComponentTwo's MethodTwo()");
    }
}

public class SubSystemThree {
    public void MethodThree() {
        System.out.println("Called SubSystemComponentThree's methodThree()");
    }
}

public class SubSystemFour {
    public void MethodFour() {
        System.out.println("Called SubSystemComponentFour's MethodFour()");
    }
}

public class Facade {

    private SubSystemOne componentOne;
    private SubSystemTwo componentTwo;
    private SubSystemThree componentThree;
    private SubSystemFour componentFour;

    public Facade() {
        componentOne = new SubSystemOne();
        componentTwo = new SubSystemTwo();
        componentThree = new SubSystemThree();
        componentFour = new SubSystemFour();
    }

    public void MethodA() {
        componentOne.MethodOne();
        componentTwo.MethodTwo();
        componentThree.MethodThree();
    }

    public void MethodB() {
        componentTwo.MethodTwo();
        componentThree.MethodThree();
        componentFour.MethodFour();
    }
}

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

        // 客户端只需要调用外观类提供的接口
        facade.MethodA();
        facade.MethodB();
    }
}

模式应用后案例

上述电商领域的案例,在应用外观模式之后的代码实现如下。

库存子系统、支付子系统和物流子系统的代码不变。

public class InventorySystem {//库存子系统

    public void updateInventory(String product, int quantity) {
        System.out.println("Updating inventory for " + product + ": " + quantity);
    }

}

public class PaymentSystem {//支付子系统

    public void processPayment(double amount) {
        System.out.println("Processing payment: $" + amount);
    }

}

public class ShippingSystem {//物流子系统

    public void shipOrder(String address) {
        System.out.println("Shipping order to address: " + address);
    }

}

按照外观模式,增加了一个外观类。

public class OrderFacade {//订单外观类

    private final InventorySystem inventory;
    private final PaymentSystem payment;
    private final ShippingSystem shipping;

    public OrderFacade() {
        this.inventory = new InventorySystem();
        this.payment= new PaymentSystem();
        this.shipping= new ShippingSystem();
    }

    //提供一个简化方法来处理整个订单流程
    public void placeOrder(String product, int quantity,double amount,String address){
        this.inventory.updateInventory(product,quantity);
        this.payment.processPayment(amount);
        this.shipping.shipOrder(address);
    }
}

最后,调用方代码修改如下。

public class Client {

    public static void main(String[] args) {
        //使用外观模式进行下单操作
        OrderFacade facade= new OrderFacade();
        facade.placeOrder("Computer", 1, 1500.00,"123 Main Street");
    }
}

可以看到,代码的复杂性已经挪到外观类中实现,调用方代码变得非常简洁清晰。

适用场景

外观模式适用于以下场景:

1、多个子系统或接口需要通过一定的交互共同为调用方服务,如果希望子系统后续可以相对调用方独立进行演进,可以考虑外观模式

2、需求实现新功能时,需要依赖企业中的遗留系统的功能。由于遗留系统通常后续会安排下线。此时就不建议将遗留系统的接口直接对调用方暴露,而是在一个外观类中封装新增加的功能和遗留系统功能

模式可能存在的困惑

困惑1:外观模式定义中提到的“界面”,具体是什么含义?

在外观模式中,多个子系统属于一个大的系统。界面可以理解为这个大系统对外暴露的契约接口。调用方只能通过界面来与系统进行交互。

本质

对于一个系统来讲,对外暴露清晰简洁的接口是非常有必要的。这不仅可以节省与调用方的沟通成本,也可以与调用方相对解耦,以便后续独立进行演进。

在系统建设初期,和调用方会制定契约接口。但是随着系统功能越来越多,经常会发现调用方需要依赖的接口越来越多,此时就可以将相互有关系的接口,再通过外观类这一层进行再封装,始终保持对外的简洁性。

此外,在外观模式下,外观类通常并不新增功能,仅仅是封装已有多个子系统的交互关系。

责任编辑:武晓燕 来源: 今日头条
相关推荐

2024-05-09 09:09:19

组合模式对象

2024-05-13 10:45:25

中介模式面向对象数量

2024-05-11 14:18:44

迭代器模式业务

2024-05-17 10:08:59

享元模式分类方式

2024-05-15 17:41:37

备忘录模式多线程

2019-08-27 14:46:59

ElasticSearES数据库

2020-07-10 08:03:35

DNS网络ARPAne

2023-05-29 08:45:45

Java注解数据形式

2019-09-09 11:02:17

Nginx进程模型

2023-03-13 08:12:37

Golang编程路径问题

2023-11-06 09:06:54

分布式一致性数据

2021-05-06 08:03:07

IPIP网络模式calicok8s

2022-05-30 10:37:35

分布式事务反向补偿

2020-12-07 06:19:50

监控前端用户

2021-07-08 10:08:03

DvaJS前端Dva

2021-06-30 08:45:02

内存管理面试

2023-10-27 08:15:45

2020-03-18 14:00:47

MySQL分区数据库

2022-06-07 10:13:22

前端沙箱对象

2019-11-06 17:30:57

cookiesessionWeb
点赞
收藏

51CTO技术栈公众号