design patterns experience

 设计模式 

分类

创建型:就是创建对象的模式,抽象了实例化的过程,对创建对象进行了封装

工厂、单例、建造者

结构型:为解决怎样组装现有的类,设计它们的交互方式,从而达到实现一定的功能目的。包容了对很多问题的解决(扩展性、封装)

适配器、装饰器、代理模式

行为型:行为型模式涉及到算法和对象间职责的分配,以及它们之间的通信模式

策略、模板方法模式、观察者模式、责任链模式

  1. 创建型模式为其他两种模式使用提供了环境。
  2. 结构型模式侧重于接口的使用,它做的一切工作都是对象或是类之间的交互,提供一个门。
  3. 行为型模式顾名思义,侧重于具体行为,所以概念中才会出现职责分配和算法通信等内容。

参考:设计模式分类(创建型模式、结构型模式、行为模式) · Issue #2 · jiayisheji/blog · GitHub

单例模式(看dcl 及静态内部类的实现)

单例模式:确保一个类只有一个实例,而且自行实例化,并向整个系统提供这个实例。

单例模式的视频:https://www.bilibili.com/video/BV1Ta4y1Y7af

分为懒汉、饿汉、双重检查锁模式。

双重检查锁模式的成员变量要加volatile 关键字进行修饰,为了防止指令重排序。

原因:

new 一个对象的时候,分为三个步骤:分配内存;初始化对象;指向刚分配的地址。

如果发生指令重排序,那么第二步和第三步可能会变化,就导致对象没有初始化成功。

单例模式三个步骤

1. 一个成员对象

2. 私有构造方法

3. get 函数(可自定义各种逻辑)

几种类型的单例模式,参考:https://www.cnblogs.com/javastack/p/12579198.html




一、懒汉:使用的时候才创建实例

不同种的懒汉单例模式的特点:

1. 声明一个实例

2. 私有构造方法

3. get 函数



实现方式1

public class Singleton {
    private static Singleton instance;
    // 私有构造方法,使用的时候不可以使用new 来创建对象
    private Singleton() {}
    public static Singleton getInstance() {
        if (null == instance) {
            instance = new Singleton();
        }
        return instance;
    }
}


线程不安全,不可用



实现方式2

public class Singleton {
    private static Singleton instance;
    // 私有构造方法,使用的时候不可以使用new 来创建对象
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (null == instance) {
            instance = new Singleton();
        }
        return instance;
    }
}

get 方法添加synchronized 关键字,线程安全,效率低,不推荐



实现方式3

public class Singleton {
    private static Singleton instance;
    // 私有构造方法,使用的时候不可以使用new 来创建对象
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

线程不安全,会产生多个实例,不可用




二、饿汉模式:无线程安全问题,不能延迟加载,影响系统性能


public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}

无线程安全问题,不能延迟加载,影响系统性能




三:双重校验锁


public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (null == instance) {
            synchronized (Singleton.class) {
                // 只有一个线程能进到这里面
                if (null == instance) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}


由于jvm 存在乱序执行的功能,DCL 也会存在线程不安全的情况,分析:

对于instance = new Singleton();
jvm 中执行分为三个步骤
1. 堆内存开辟内存空间
2. 堆内存中实例化SingleTon 各个参数
3. 把对象指向堆内存空间
可能存在先执行了3,再执行2。
如果此时再被切换到线程B 上,由于执行了3,instance 已经非空,那么就会被直接拿出来用。
这样就会出现异常,这就是著名的DCL 失效问题。
然后对于成员变量加了volatile 之后,确保instance 每次都在主内存中读取,牺牲一些效率。
加了volatile 是为了禁止指令重排序


DCL,线程安全,推荐使用




四、静态内部类


public class Singleton {
    private static class SingletonHolder {
        private static Singleton INSTANCE = new Singleton();
    }
    private Singleton () {}

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

线程安全,主动调用的时候才会被实例化,延迟加载效率高,推荐使用
实现原理,参考:https://blog.csdn.net/qq_43279637/article/details/84982874
可能博文有错误,但是能看清楚原理

https://blog.csdn.net/mnb65482/article/details/80458571
这个文章原理写的清楚,但是没看。

问题:这种情况如何保证线程安全
总结:是虚拟机保证的,如果多线程同时去初始化一个类,内么只有一个线程会执行<clinit> 方法,其他都要阻塞。




五、枚举单例


public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  

    }  
}

很少用,枚举在java中与普通类一样,都能拥有字段与方法,而且枚举实例创建是线程安全的,在任何情况下,它都是一个单例。我们可直接以
SingleTon.INSTANCE
的方式调用。



Q9:单例模式有哪些实现?
饿汉式:在类加载时就初始化创建单例对象,线程安全,但不管是否使⽤都创建对象可能会浪费内存。

懒汉式:在外部调⽤时才会加载,线程不安全,可以加锁保证线程安全但效率低。

双重检查锁:使⽤ volatile 以及多重检查来减⼩锁范围,提升效率。

静态内部类:同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。

枚举:《Effective Java》提倡的⽅式,不仅能避免线程安全问题,还能防⽌反序列化重新创建新的对象,绝对防⽌多次实例化,也能防⽌反射破解单例的问题。

工厂模式(三种)

创建对象变得简单而且修改对象时能很方便

工厂模式解耦的意思是:

举例如果一个类中,使用了某个对象,要new 一个这个对象,那么这个类和这个依赖的对象对应的类就是“耦合”的关系。

如果一个类,使用了工厂

  • 简单工厂模式
    (工厂是个类,负责创建具体的产品;)
    (工厂中的方法返回的也是产品)
    (产品肯定有统一的接口,每个具体的产品实现产品接口)
  • 工厂方法模式
    (工厂是个接口,具体产品工厂实现工厂接口)
    (工厂接口中的方法返回的是产品)
    (产品肯定也是有个统一的接口,每个产品实现产品接口,由具体产品工厂创建)
  • 抽象工厂模式
     

看这个链接也不错:简单工厂模式、工厂方法模式和抽象工厂模式有何区别? - 知乎

简单工厂模式,又称静态工厂方法模式。此模式中,可以根据参数的不同,返回不同的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,创建出来的类通常具有共同的父类。
这个专门定义的工厂类处于对产品进行实例化的中心位置,即它需要知道产品类的具体实现细节,并决定何时实例化哪一个产品类。

每当有新产品加入时,必须要修改工厂类。
参考视频:五分钟学设计模式.02.简单工厂模式_哔哩哔哩_bilibili
 

简单工厂模式分为几个内容:

  1. 一个实体的工厂类,里面有个create 方法,根据方法传参,决定返回那个具体的角色类
  2. 各个角色的统一接口
  3. 各个角色的具体实现类

工厂方法模式,定义一个用于创建对象的接口,让这个接口的子类决定实例化哪个产品类。工厂方法使一个类的实例化延迟到子类。即新增一个产品的时候,不需要再去修改工厂类,不需要再去修改if else 了。


相对于简单工厂模式,之前的核心工厂变成了一个抽象接口,负责给出工厂应该实现的方法,不再负责所有产品的创建,将具体的产品创建工作交给子类去做。这样就诞生了具体的子工厂,即子类负责生产具体的产品对象。这样做可以将产品类的实例化操作延迟到工厂子类中完成。即通过工厂子类来确定究竟该实例化哪个具体实例类。(开闭原则)

 

这是工厂类的实现代码,但是只能创建一个大类的产品

当创建逻辑比较复杂,不只是简单地new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,推荐使用“工厂方法模式”,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。而简单工厂模式是把所有创建逻辑都放到同一个类中,会导致这个工厂类变得很复杂。

工厂方法分为几个内容:

  1. 工厂类的接口,里面有个方法,如“创建动物”
  2. 各个具体角色的类工厂,如猫工厂、狗工厂,返回猫类、狗类
  3. 角色的接口,如Animal
  4. 各个角色的具体实现类

工厂方法模式参考这个图就好

 抽象工厂模式
 打破了上述工厂与产品的一对一的关系,而这个是一个具体的工厂类可以生产多个大类的产品。
扩展了具体工厂的功能,使其可以生产多个大类。

 

 从类图可以看出,新增一个产品体系,就必须要对工厂类进行修改。也就是说一旦要新增一个产品体系的话,就必须要修改原有的工厂逻辑。包括抽象接口以及所有具体工厂。

对比于“工厂方法模式”的区别就是

工厂方法模式,如果有很多个角色,就要有很多个具体角色的工厂类

抽象工厂模式就是把各个具体角色的工厂的共性抽出来,比如说猫、狗,不是公的就是母的

抽象工厂模式分为如下的内容:

  1. 工厂的接口,里面定义的是创建各个角色的接口,每个接口返回一个角色(如猫、狗)
  2. 抽象出来的属性的具体工厂,如抽象出来动物的性别,所有就是“母动物工厂具体实现类”,“公动物具体工厂实现类”
  3. 角色的接口(抽象类),接口中的方法是每个角色都具有的共性行为(如吃的动作,返回性别 两个接口)
  4. 对于角色的大类分别,对于每种类型的角色,如“猫”,吃的动作返回“吃鱼”,这是所有猫角色共同的
  5. 对于角色的另外一个分别,比如说分为“公猫”,“母猫”

个人理解:
抽象工厂模式就是抽象出来“产品族”的概念,将原来一个产品一个工厂类的情况改成一类产品一个工厂实现类
可以参考看看这个:https://www.zhihu.com/question/27125796/answer/688147580

装饰器模式

给一个类或者对象增加新的功能有两种方式
一种称为“继承机制”,在子类扩展功能;第二种称为“关联机制”,把一个类的对象嵌入到另一个类的对象中。
对于继承,是静态的,必须要实现子类,对类的层级进行扩展。
对于装饰器模式,是动态的,拿到一个对象就可以对其进行扩展,不需要修改原有类逻辑。

其中,Decorator 也是Component 的实现;ConcreteComponent 也是Component 的具体实现。

 
java IO 流用了装饰器模式。

责任链模式(因为Filter 使用了)


参考视频:五分钟学设计模式.12.责任链模式_哔哩哔哩_bilibili

 

客户请求:

 优点,将请求和处理分开。请求者不需要知道谁去处理,处理者不需要知道请求全貌。可以提高系统灵活性,新增一个处理器,到系统中代价是非常小的。

缺点,会降低系统性能。如果某个请求,直接找boss 就好。请求需要从链头走到链尾。

模板方法模式


参考视频:五分钟学设计模式.13.模板方法模式_哔哩哔哩_bilibili

最重要的特点就是,行为步骤由父类去控制,子类去负责实现 。
父类中封装了不变的部分,子类通过扩展父类, 扩展具体的实现,实现更进一步的操作。

缺点:增加系统复杂度(无大碍)。

建造者模式

将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

public class StudentQueryCondition {
    /**
     * 必填字段
     */
    private Long id;
    /**
     * 选填字段
     */
    private String name;
    private Integer age;
    private String address;
    private String school;
    
    private StudentQueryCondition(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.age = builder.age;
        this.address = builder.address;
        this.school = builder.school;
    }
    
    public static Builder builder(Long id) {
        return new Builder(id);
    }
    
    public static class Builder {
        // 必填字段
        private Long id;
        // 选填字段
        private String name;
        private Integer age;
        private String address;
        private String school;
        private Builder(Long id) {
            this.id = id;
        }
        public Builder name(String name) {
            this.name = name;
            return this;
        }
        public Builder age(Integer age) {
            this.age = age;
            return this;
        }
        public Builder address(String address) {
            this.address = address;
            return this;
        }
        public Builder school(String school) {
            this.school = school;
            return this;
        }
        public StudentQueryCondition build() {
            return new StudentQueryCondition(this);
        }
    }
}

代理模式

  1. 静态代理
    client 调用静态代理对象的方法。创建一个静态代理类,将被代理对象(目标对象)传入,然后创建需要增强的方法
     
  2. 动态代理
    和静态代理本质一样,只不过静态代理采用硬编码的方式,在程序运行前就创建好代理类,

设计模式相关可以参考的链接:https://blog.csdn.net/mengchuan6666/article/details/119924760

转换器模式

转换器(Converter)设计模式 - TSMYK的个人空间 - OSCHINA - 中文开源技术交流社区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值