前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于设计模式的那些事(一)

关于设计模式的那些事(一)

作者头像
Bruce Li
发布2020-09-17 14:36:13
3820
发布2020-09-17 14:36:13
举报

通常我们说的设计模式,指的是GoF23(Gang of Four),包括23个常用的设计模式。这里尝试从不同的角度聊一聊其中几个设计模式。

1. 单例模式

单例模式可能是一个程序员最早接触的设计模式之一,因为这个设计模式适用的场景非常广泛。比如,在Spring中,我们可以加注@Scope annotation来设置一个bean是”单例“或者”多例“,默认是单例。

单例模式有多种实现方式,其中常见的一种方式,如下:

代码语言:javascript
复制
public class Singleton {
    private static Singleton mySingleton;

    private Singleton() {
    }

    public synchronized Singleton getInstance() {
        if (null == mySingleton) {
            mySingleton = new Singleton();
        }
        return mySingleton;
    }
}

基于这种方式,每次调用getInstance都需要加锁,性能会受到很大的影响。所以,就有了下面这种基于双重检查锁的方式:

代码语言:javascript
复制
public class Singleton {
    private static Singleton mySingleton;

    private Singleton() {
    }

    public Singleton getInstance() {
        if (null == mySingleton) {
            synchronized (Singleton.class) {
                if (null == mySingleton) {
                    mySingleton = new Singleton();   // error
                }
            }
        }
        return mySingleton;
    }
}

这种(double checked locking)方式,解决了上面提到的性能问题。但是,由于JVM的指令重排序机制,上面的方式在某些情况下可能不工作,具体解释可以参考:

  • https://www.cnblogs.com/xz816111/p/8470048.html
  • https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

那么,解决方案就是在mySingleton变量申明前加上volatile(JDK1.5之后),如下:

代码语言:javascript
复制
public class Singleton {
    private volatile static Singleton mySingleton;

    private Singleton() {
    }

    public Singleton getInstance() {
        if (null == mySingleton) {
            synchronized (Singleton.class) {
                if (null == mySingleton) {
                    mySingleton = new Singleton();
                }
            }
        }
        return mySingleton;
    }
}

2. 代理模式

代理,对应的英文单词是”proxy“。提到代理,可能我们首先想到的是如果要访问google,需要设置一个代理,如下:

设置了这个代理之后,我们访问网址的所有请求,都会先经过这个代理服务器,然后由它帮忙转发到相应的网址服务器;处理完成之后,按原路返回给用户。代理服务器在转发请求之前,可能会做一些额外逻辑,比如:权限校验,限制只有付费用户才可以使用这个代理。

除此之外,我们可能还听过一个术语:反向代理reverse proxy,nginx就是一个流行的用于实现反向代理的开源软件;还有,在之前的一篇文章中(这些年我对微服务的理解)提到的API Gateway,其实也实现了reverse proxy的功能。所以,这里的proxy和上面的代理有些类似,都是帮忙转发请求到具体的请求处理服务器,并且对请求做一些额外的处理。

其实,代理模式原理上跟上面的例子类似,从编程角度讲,代理类在执行本来要代理的方法之前或者之后增加一些切面方法,以实现一些额外功能,比如打印日志等。

代理的实现,可以分为静态代理和动态代理。JDK提供了一个Proxy类,用于实现动态代理。Spring的AOP面向切面编程,底层就是基于JDK的动态代理或者CGLIB。

3. 观察者模式

简单讲,可以把观察者模式理解成事件监听机制,当一个事件发生时,触发所有提前注册好的监听方法。比如:Spring JPA的@PostPersist、@PostUpdate,当一个entity被持久化或者更新之后,加注了相应annotation的方法就会被执行。在很早之前用过JMX来实现Java进程的monitoring功能,JMX里面的Notification机制也即是基于观察者模式。还有,当我们点击UI上的一个button按钮,即会触发提前注册的相应callback方法,也是类似的原理。

同时,可以把观察者模式和现在常用的pub-sub模式做类比理解,它们有异曲同工之处。

4. 模版方法模式

我们平时工作中很多地方都有用到模版方法模式,比如:在Spring中,一个Bean的life cycle都会由容器负责执行init和destroy方法,而这两个方法可以在每个Bean定义的时候重写,这和c++里面类的构造方法、析构方法有些类似。同样的,SAP UI5里面的controller的life cycle也都会按顺序执行onInit、onBeforeRendering、onAfterRendering和onExit这几个方法,任何自己写的controller都可以重写。

5. 建造者模式

对于一个包含很多属性的复杂POJO,在创建一个对象的时候,我们调用setter方法去给相应的属性赋值,有时候代码会显得比较冗余,如下:

代码语言:javascript
复制
Person p = new Person();
p.setAttribute1("a1");
p.setAttribute2("a2");
p.setAttribute3("a3");
p.setAttribute4("a4");

这时我们就可以采用建造者模式,如下:

代码语言:javascript
复制
Person p = Person.builder().attribute1("a1").attribute2("a2").attribute3("a3").attribute4("a4").build();

一定程度来说,这种链式编程的方式显得简洁一些。如果使用Lombok,我们可以开箱即用的使用建造者模式,只需要在POJO类上加注一个@Builder annatation即可。

还有一个我们最熟悉的StringBuilder也是应用了这个模式,用于构造一个String对象。

References

  • https://docs.microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/direct-client-to-microservice-communication-versus-the-api-gateway-pattern
  • https://projectlombok.org/features/Builder
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 天马行空布鲁斯 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档