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

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

​ 门面模式(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 接口就会调用插件中的实现方法

调用接口

相关推荐
xiaolizi5674891 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100011 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜1 小时前
Python入门篇【文件处理】
android·java·python
遥不可及zzz4 小时前
Android 接入UMP
android
Coder_Boy_6 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab6 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言
冬奇Lab6 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
冬奇Lab7 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化
GISer_Jing8 小时前
AI Agent 目标设定与异常处理
人工智能·设计模式·aigc