前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >设计模式觉醒系列(02)这几种设计模式很简单实用 | 相信你肯定见过

设计模式觉醒系列(02)这几种设计模式很简单实用 | 相信你肯定见过

原创
作者头像
拉丁解牛说技术
发布2025-03-06 11:22:29
发布2025-03-06 11:22:29
1500
举报

读书笔记:“幸福并非瞬间发生,他与运气、概率无关,用钱买不到,也不能倚仗权势巧取豪夺。它不受外在事物操纵,而取决于我们对外在事物的阐释”。这句话触动很大,很多时候的精神内耗,无妄的想象揣测导致我们对外在的看法变得消极。阿德勒心理学提出的目的论,引导我们的就是改变自己对外在事物的阐释,从而做到他者信赖、他者贡献,主动去改变自己,也可以改变世界,建立维护双向的良好关系。


一、前言背景

二、模板方法模式

2.1 实战demo-场景

2.2 模板方法模式的优点

2.3 tomcat 源码应用模板模式

三、外观模式(门面模式)

3.1 实战demo-场景

3.2 外观模式的优点

3.3 tomcat 源码应用外观模式

四、单例模式

4.1 实战demo-场景

4.1.1 线程不安全-懒汉单例

4.1.2 线程安全-懒汉-单例模式

4.1.3 线程安全-饿汉-单例模式

4.2 单例模式优点

4.3 Spring 源码应用单例模式


一、前言背景

在上一篇系列文章《设计模式觉醒系列(01)设计模式的基石 | 六大原则的核心是什么?》,我们已经详细分享了设计模式的六大原则,以及总结设计模式在研发设计过程中的核心作用。可以说,设计模式就是专门帮我们解决设计问题的经典方案,也是帮助研发人员提高代码可复用性、可维护性、可扩展性、可阅读性的内功心法。

设计模式总共有20多种,如果一篇一篇来写,可以写很长时间,读者也可以订阅关注很长时间。实际而言,很多设计模式都是基于六大基本原则衍生出来,都有共性,为了减少阅读疲劳,以及帮助有缘同学尽快掌握了解齐全这20多种设计模式,后续每篇文章,我们尽量至少分享2个设计模式,期望10篇左右分享完毕。今天我们一次分享三个最简单实用、又非常接地气的设计模式,相信你一定都见过、用过。

附带多说一句,每个设计模式并非完美,都有优缺点。没有绝对的完美解决方案,唯有合适的业务场景应用合适的设计模式,争取最佳实践效果。

二、模板方法模式

模板方法模式(Template Method Pattern),英文原义是:定义一个算法的框架,将一些步骤的实现,延迟到子类中去。在模板方法模式里,父类定义了一个模板方法(它真的就是一个方法method()),然后在这个方法里包含了一系列的操作,比如按顺序调用方法a、b、c、d。而其中的某些操作父类并没有实现,并定义为抽象方法,让子类去实现。

比如以下非常简单的demo,定一个美好一天的抽象类,里面有个模板方法start(),模板方法里按顺序调用了起床、刷牙、吃早餐的方法。

其他三个方法,父类已经实现起床方法getup()+一个吃早餐方法eatBreakfast(),而刷牙方法延迟给子类去实现。

代码语言:java
复制
// 抽象美好一天类
abstract class AbstractNiceDay {
    // 模板[方法],定义一天的开始,需要起床,刷牙,吃早餐
    public final void start() {
        getup();
        brushtooth();
        eatBreakfast();
    }

    // 起床,公共方法,父类已经实现好
    private void getup() {
        System.out.println("拉丁解牛说技术,每个人早上都会起床");
    }
    // 刷牙,抽象方法,由子类实现,有一些人可能不爱刷牙,比如小朋友
    protected abstract void brushtooth();
    
    // 吃早餐,公共方法,父类已经实现好
    private void eatBreakfast() {
        System.out.println("拉丁解牛说技术,每个人早上都吃早餐");
    }

具体应用,如果小火、小美他们都开启美好的一天,就分别继承这个相信这个AbstractNiceDay父类,实现里面刷牙方法就可以复用父类的模板方法start()正式开启快乐的一天。这个很直观,大家都能理解,也就不用画图说明。

2.1 实战demo-场景

假如我们需要设计开发一个文档生成器,文档生成包括新建具体文档、文档增加水印标签、保存文档三个步骤。

代码语言:java
复制
package lading.java.designpattern.templatemethod;

/**
 * 业务场景:文档生成器,支持PDF,word,excel,csv,ppt等文件
 * 文档处理器-抽象类
 * 包含三个步骤,
 * 1、生成具体文档
 * 2、文档加水印
 * 3、保存文档
 */
public abstract class AbstractDocumentGenerator {
    //定义模板方法,按顺序生成文档
    public final void generateDocument() {
        createDocument();
        addTarget();
        saveDocument();
    }

    //子类自己实现
    protected abstract void createDocument();

    //文档加水印,已实现
    protected void addTarget() {
        System.out.println("给文档内容加拉丁解牛说技术的水印或者标识");
    }

    protected void saveDocument() {
        System.out.println("保存文档到固定文档目录/file/ladingjieniu/doc");
    }
}

package lading.java.designpattern.templatemethod;

/**
 * 业务场景:文档生成器,支持PDF,word,excel,csv,ppt等文件
 * 文档处理器-抽象类
 * 包含三个步骤,
 * 1、生成具体文档
 * 2、文档加水印
 * 3、保存文档
 */
public abstract class AbstractDocumentGenerator {
    //定义模板方法,按顺序生成文档
    public final void generateDocument() {
        createDocument();
        addTarget();
        saveDocument();
    }

    //子类自己实现
    protected abstract void createDocument();

    //文档加水印,已实现
    protected void addTarget() {
        System.out.println("给文档内容加拉丁解牛说技术的水印或者标识");
    }

    protected void saveDocument() {
        System.out.println("保存文档到固定文档目录/file/ladingjieniu/doc");
    }
}

2.2 模板方法模式优点

子类可以在严格遵守父类(或者说算法)模板结构的前提下,重新自定义实现具体的某些步骤。这里充分体现了六大核心原则的开闭原则(OCP),对具体步骤实现修改开放,对模板规则框架修改封闭。

此外也提高代码的复用性,子类复用父类已实现的部分步骤方法,减少代码编写。

以及也提高代码可扩展性。

2.3 tomcat 源码应用模板模式

在tomcat源码里,javax.servlet.http.HttpServlet 类的service方法,也是应用了模板方法。service()方法就是个模板方法,他会根据不同请求类型调用相应的处理方法。而里面调用的具体方法,比如doGet、doPost,这些方法在子类可以自定义去实现。源码:

三、外观模式(门面模式)

外观模式(facade),也叫门面模式。它的定义是:一个子系统的外部与其内部的通信必须通过一个统一的对象进行。具体是:外观模式为子系统的一组接口提供一个高层次的接口(IFacade,或者定一个xxFacade外观类)。这样可以隐藏子系统的复杂性,使得子系统更易于使用。当客户端调用子系统时候,只需要通过这个高层次的外观接口(Facade类)就可以调用子系统的功能,从而达到客户端与子系统解耦。

比如说一会3.1例子demo的订单系统,订单系统有支付、库存、物流分配三个子系统功能,外部第三方平台需要调用我们订单系统下定单。我们可以定义一个专门处理订单的OrderFacade类,封装好三个功能,供外部客户端去调用。

3.1 实战demo-场景

具体如下,通过OrderFacade类封装好底层内部的支付、物流、库存管理功能。外部client只需要调用OrderFacade类就可以实现下单功能。

代码语言:java
复制
package lading.java.designpattern.facade;

/**
 * 物流分配子模块
 */
public class LogisticsService {
    public void assignExpress(){
        System.out.println("说技术拉丁分配物流公司接单安排派送");
    }
}

package lading.java.designpattern.facade;

/**
 * 支付服务模块
 */
public class PayService {
    public void processPay(){
        System.out.println("拉丁处理订单支付扣款事宜");
    }
}


package lading.java.designpattern.facade;

/**
 * 库存管理模块
 */
public class StoreService {
    public void deductProd(){
        System.out.println("ladingjieniu 减少产品库存");
    }
}


package lading.java.designpattern.facade;

/**
 * 内部订单系统门面-外观类
 */
public class OrderFacade {
    //内置相关子类功能
    private LogisticsService logisticsService = new LogisticsService();
    private PayService payService = new PayService();
    private StoreService storeService = new StoreService();

    public void processOrder() {
        payService.processPay();
        storeService.deductProd();
        logisticsService.assignExpress();
    }

    /**
     * 客户端调用下单
     *
     * @param args
     */
    public static void main(String[] args) {
        OrderFacade facade = new OrderFacade();
        facade.processOrder();
    }
}

3.2 外观模式的优点

外观模式非常像公司内部的门户,通过提供高层次的外观模式类,隐藏子系统的交互细节,有效降低客户端与内部模块的耦合度。

由于解耦,子系统的修改,不影响外观类,也不影响客户端的调用,提高代码的可扩展性、可维护性。

外观模式充分体现了依赖倒转原则(细节依赖抽象,降低模块依赖)和迪米特法则(最少知道,一个类对另一个类知道越少越好)的思想。

3.3 tomcat 源码应用外观模式

在tomcat源码里,RequestFacade就是外观模式的经典标准应用。RequestFacade实现了HttpServletRequest接口,底层封装了Request对象,客户端ApplicationDispatcher在应用Request时候,就不需要关系Request的底层逻辑,通过RequestFacade类就可以调用,实现解耦。

此外tomcat里的ResponseFacade、StandardSessionFacade都是用了外观模式。

四、单例模式

单例模式,singleton pattern,原义很简单:确保一个类只有一个实例,并自行实例化给整个系统使用。这个特点决定里单例模式适合在对资源开销敏感、要求资源共享复用场景下应用,比如缓存、静态资源。

单例模式有几种实现方式,一个是懒汉模式,等需要用到实例的时候再去实例化,这种模式需要注意线程安全。另一个是饿汉模式,在类加载的时候就实例化对象,这种是线程安全的。接下来对这两种模式的三个案例提供demo分享。

4.1 实战demo-场景

4.1.1 线程不安全-懒汉单例

代码语言:java
复制
package lading.java.designpattern.singleton;

/**
 * 并发不安全,单例模式
 */
public class UnsafeSingleton {
    private static UnsafeSingleton singleton;
    //避免外部构造多个对象
    private UnsafeSingleton() {

    }
    //仅该方法可以获得实例
    public static UnsafeSingleton getSingleton() {
        //多个线程同时执行到这部分,就会出现多个实例
        if (singleton == null) {
            singleton = new UnsafeSingleton();
        }
        return singleton;
    }
}

4.1.2 线程安全-懒汉-单例模式

代码语言:java
复制
package lading.java.designpattern.singleton;

/**
 * 懒汉单例,双重检查,线程安全的单例模式
 */
public class SafeSingletonLazy {
    private static volatile SafeSingletonLazy singleton;
    //私有,防止外部实例化
    private SafeSingletonLazy() {

    }

    public static SafeSingletonLazy getSingleton() {
        if (singleton == null) {
            synchronized (SafeSingletonLazy.class) {
                if (singleton == null) {
                    singleton = new SafeSingletonLazy();
                }
            }
        }
        return singleton;
    }
}

4.1.3 线程安全-饿汉-单例模式

代码语言:java
复制
package lading.java.designpattern.singleton;

/**
 * 饿汉-单例模式,线程安全
 * 单例对象在加载的时候就实例化好该实例,线程安全
 */
public class SafeSingletonHungry {
    private static final SafeSingletonHungry singletonHungry = new SafeSingletonHungry();

    //私有化,防止外部实例化
    private SafeSingletonHungry() {

    }

    public static SafeSingletonHungry getInstance() {
        return singletonHungry;
    }
}

4.2 单例模式优点

通过确保一个类在整个应用程序生命周期里只有一个实例对象,直接好处就是减少创建对象的开销,为系统节省资源。

4.3 Spring 源码应用单例模式

我们熟悉的spring的IOC容器的实例管理有经典实践,@Bean默认就是单例模式,也可以通过@Scope("prototype")进行修改。


推荐阅读拉丁解牛相关专题系列(欢迎交流讨论公众号搜:拉丁解牛说技术)

1、JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC

2、JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?

3、JVM进阶调优系列(3)堆内存的对象什么时候被回收?

4、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

5、JVM进阶调优系列(1)类加载器原理一文讲透

6、JAVA并发编程系列(13)Future、FutureTask异步小王子

7、MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合

8、MySQL进阶突击系列(09)数据磁盘存储模型 | 一行数据怎么存?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言背景
  • 二、模板方法模式
    • 2.1 实战demo-场景
    • 2.2 模板方法模式优点
    • 2.3 tomcat 源码应用模板模式
  • 三、外观模式(门面模式)
    • 3.1 实战demo-场景
    • 3.2 外观模式的优点
    • 3.3 tomcat 源码应用外观模式
  • 四、单例模式
    • 4.1 实战demo-场景
      • 4.1.1 线程不安全-懒汉单例
      • 4.1.2 线程安全-懒汉-单例模式
      • 4.1.3 线程安全-饿汉-单例模式
    • 4.2 单例模式优点
    • 4.3 Spring 源码应用单例模式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档