设计模式第五章(门面模式)

设计模式第五章(门面模式)

​ 门面模式(Facade Pattern)是一种结构型设计模式,它为子系统中的一组接口提供了一个统一的高层接口,使得子系统更容易使用。

门面模式主要包含以下几个角色:

  • Facade(门面角色):是门面模式的核心,为子系统提供统一接口,屏蔽子系统的复杂性。它知道哪些子系统负责处理请求,并将请求代理给适当的子系统对象。
  • SubSystem Classes(子系统角色):实现子系统的功能,这些子系统对客户端来说是黑盒,客户端通过门面角色与它们交互。
  • Client(客户角色):与门面角色交互,无需了解子系统的具体实现。

​ 例如,在一个电商系统中,订单处理涉及库存系统、支付系统、物流系统等多个子系统。可以设计一个订单处理门面,将这些子系统的功能整合在一起,客户端只需与订单处理门面交互,无需了解库存、支付、物流等子系统的具体实现细节,就能完成订单处理的操作。

门面模式的优点包括简化客户端调用、减少系统依赖、提高代码的可维护性和可读性等。缺点是不符合开闭原则,当增加子系统和扩展子系统行为时,可能需要修改门面类,并且在某些情况下,可能会导致门面类变得庞大,承担过多的责任。

引言

我们模拟一个mysql 和tomcat 的启动过程,mysql 的启动过程是不是分为好几个步骤,tomcat 启动是不是也分为多个步骤,接下来我们用代码表示一下。

mysql 启动过程

java 复制代码
public class Mysql {


    public void initData() {
        System.out.println("初始化mysql......");
    }


    public void checkLog() {
        System.out.println("校验日志,恢复未提交的数据......");
    }


    public void unlock() {
        System.out.println("释放锁");
    }


    public void listerPort() {
        System.out.println("监听端口 3306 ");
    }
}

tomcat 启动过程

java 复制代码
public class MyTomcat {

    public void initEngine() {
        System.out.println("初始化tomcat引擎....");
    }

    public void initWeb() {
        System.out.println("加载web应用。。。");
    }
}

客户端调用

java 复制代码
public class Main {

    public static void main(String[] args) {
        Mysql mysql = new Mysql();
        mysql.initData();
        mysql.checkLog();
        mysql.unlock();
        mysql.listerPort();

        System.out.println("-------------->");
        MyTomcat tomcat = new MyTomcat();
        tomcat.initEngine();
        tomcat.initWeb();
    }
}

问题点

​ 我们看到,作为第一个客户端,我们调用需要经过多个步骤,有没有一种简单的方法,我们只需要调用,某一个方法就能实现这种场景呢,那么接下来就是一个门面的封装了。

门店模式封装启动过程

  • 抽象启动类
  • 实现类

抽象类

我们定义了一个抽象启动的门店接口,里面只有一个方法,start()

java 复制代码
public interface ServiceFace {


    void start();
}

mysql 实现

java 复制代码
public class MySql1 implements ServiceFace {
    @Override
    public void start() {
        Mysql mysql = new Mysql();
        mysql.initData();
        mysql.checkLog();
        mysql.unlock();
        mysql.listerPort();
    }
}

tomcat实现

java 复制代码
public class MyTomcat1 implements ServiceFace {
    @Override
    public void start() {
        MyTomcat tomcat = new com.fashion.ori.MyTomcat();
        tomcat.initEngine();
        tomcat.initWeb();
    }
}

客户端

java 复制代码
public class Main {

    public static void main(String[] args) {

        ServiceFace tomcat = new MyTomcat1();
        tomcat.start();

        ServiceFace mysql = new MySql1();
        mysql.start();
    }
}

我们看到,调用的客户端只需要知道门面接口定义的抽象方法即可,这样调用的过程封装到实现里面,使客户端使用更简单。

自定义门面插件类

需求背景,我需要统计一个接口每次被调用都进行一个计次数的动作,当然我们可以直接写到方法中,但是如果这是一个插件呢,我们需要如何实现。

  • 插件api 模块
  • 插件实现类
  • 调用方

插件api

java 复制代码
public interface MyPlugin {

    void beforeGetTime();
}
xml 复制代码
    <modelVersion>4.0.0</modelVersion>
   
       <groupId>com.fashion</groupId>
       <artifactId>my_plugin_api</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

插件实现类

java 复制代码
public class CountPlugin implements MyPlugin {

    AtomicInteger count = new AtomicInteger(0);

    @Override
    public void beforeGetTime() {
        System.out.println("访问次数:"+count.incrementAndGet());
    }
}
xml 复制代码
    <artifactId>count_plugin</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.fashion</groupId>
            <artifactId>my_plugin_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

客户端

java 复制代码
@RestController
public class TimeController {


    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    private MyPlugin myPlugin;


    @GetMapping("/time")
    public String getTime() {
        if (myPlugin != null) {
            myPlugin.beforeGetTime();
        }

        return LocalDateTime.now().format(dateTimeFormatter);
    }


    /**
     *  加载插件  必须有一个文件叫 liuqiang.plug
     */
    @GetMapping("/load/plugin/{path}")
    public String loadPlugin(@PathVariable("path") String path) {
        File file = new File("face-pattern\\face-boot\\"+path);
        try(
            URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{file.toPath().toUri().toURL()});
            InputStream lqPlugin = urlClassLoader.getResourceAsStream("chajian.plugin");
            ) {

            //插件的实现类
            String myPluginClassName = new String(lqPlugin.readAllBytes());
            Class<?> aClass = urlClassLoader.loadClass(myPluginClassName.trim());
            // 生成构建方法
            Constructor<?> constructor = aClass.getConstructor();
            myPlugin = (MyPlugin)constructor.newInstance();
            return "插件加载成功----"+aClass.getName();
        } catch (Exception e) {
           return "插件记载失败"+e.getMessage();
        }
    }


}

pom文件

xml 复制代码
 <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.fashion</groupId>
            <artifactId>my_plugin_api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.fashion.face.FaceBootApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

启动流程

我们先加载插件,当插件加载后,那么我们访问 time 接口就会调用插件中的实现方法

调用接口

相关推荐
fionlsq3 小时前
uniapp集成原生安卓开发的插件
android·uni-app·小组件
大飞pkz4 小时前
【设计模式】策略模式
开发语言·设计模式·c#·策略模式
yujkss4 小时前
23种设计模式之【状态机模式】-核心原理与 Java实践
java·ui·设计模式
风起云涌~6 小时前
【Android】kotlin.flow简介
android·开发语言·kotlin
深海呐6 小时前
Android 协程的基本使用和最简要原理概述
android·协程·android 协程·协程的原理
studyForMokey7 小时前
【Kotlin进阶】泛型的高级特性
android·开发语言·kotlin
袁震7 小时前
Android-kotlin MVVM框架搭建+Retrofit二次封装
android·kotlin·mvvm·retrofit
2501_916007478 小时前
Java界面开发工具有哪些?常用Java GUI开发工具推荐、实战经验与对比分享
android·java·开发语言·ios·小程序·uni-app·iphone