设计模式(一)之创建型模式

一、单例模式

一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。

单例特点

  • 某个类只能有一个实例;(构造器私有)·
  • 它必须自行创建这个实例;(自己编写实例化逻辑)
  • 它必须自行向整个系统提供这个实例(对外提供实例化方法)

1 饿汉式

1.1 直接赋值

饿汉代表对象随着类的加载而创建

示例

/**
 * @Description 单例对象 饿汉
 * @Date 2021/7/11 22:21
 * @author: A.iguodala
 */
public class HungrySingleton {

    /**
     * 代表一些属性
     */
    private Object data;

    /**
     * 饿汉式
     * 直接构造出该单例对象
     */
    private static final HungrySingleton singleton = new HungrySingleton();

    /**
     * 将构造器设为私有,禁止访问
     */
    private HungrySingleton() {
    }

    /**
     * 提供静态方法获取该单例对象
     * @return
     */
    public static HungrySingleton getSingleton() {
        return singleton;
    }
}

1.2 枚举

/**
 * @Description
 * @Date 2021/7/12 14:14
 * @author: A.iguodala
 */
public enum EnumSingleton {

    /**
     * 单例对象
     */
    INSATANCE;
}

2 懒汉式

懒汉式指的是当使用该对象的时候再进行创建,避免资源的浪费

但是在多线程环境下要进行加锁以及可见性判断来保证线程安全

2.1 双重检查

示例

/**
 * @Description 单例模式,懒汉
 * @Date 2021/7/11 22:38
 * @author: A.iguodala
 */
public class LazySingleton {

    /**
     * 代表一些属性
     */
    private Object data;

    /**
     * 懒汉式
     * 当使用的时候再构造该对象
     * 使用volatile保证内存语义的有序性
     */
    private volatile static LazySingleton singleton;

    /**
     * 将构造器设为私有,禁止访问
     */
    private LazySingleton() {
    }

    /**
     * 提供静态方法获取该单例对象
     * @return
     */
    public static LazySingleton getSingleton() {
        // 检查是否为空,不是则返回对象
        if (singleton == null) {
            // 加锁避免线程安全问题
            synchronized (LazySingleton.class) {
                // 双重检查,如果不为空,才创建对象
                if (singleton == null) {
                    // 这里解释为什么singleton需要加volatile关键字
                    // 因为new LazySingleton() 也并不是一个原子操作,
                    // 要进行分配内存,初始化零值,设置对象头,执行初始化方法,再赋值引用
                    // 可能会有重排序的产生,相当于在作为初始化操作之前singleton已经不是null了
                    // 所以采用volatile来保证有序性
                    singleton = new LazySingleton();
                }
            }
        }
        return singleton;
    }
}

为什么singleton对象要使用volatile关键字修饰?

因为new LazySingleton() 也并不是一个原子操作,要进行分配内存,初始化零值,设置对象头,执行初始化方法,再赋值引用的操作,可能会有重排序的产生,相当于在初始化singleton操作之前singleton已经不是null了,导致其他线程获取了没有初始化完全的对象。所以采用volatile来保证有序性

2.2 静态内部类

该方法通过静态内部类创建对象,可以实现懒加载以及,通过JVM保证类加载的线程安全来保证单例模式的线程安全


/**
 * @Description
 * @Date 2021/7/12 14:05
 * @author: A.iguodala
 */
public class StaticInnerSingleton {

    /**
     * 通过该类来构造该单例对象
     */
    private static class SingletonHolder {
        private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
    }

    /**
     * 将构造器设置为私有
     */
    private StaticInnerSingleton() {

    }

    /**
     * 获取单例对象
     * @return
     */
    public static final StaticInnerSingleton getSingleton() {
        return SingletonHolder.INSTANCE;
    }
}

二、原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。

原型模式已经深深嵌入Java中,Object的clone方法就是原型模式的表现

例如,数据库查询到的数据构建成对象之后放入缓存中,如果直接取得该对象,并进行了修改,则该缓存中的对象也被修改,形成了脏数据,应该从缓存中取得的是以该缓存对象为原型的克隆对象

示例:

import jdk.jfr.DataAmount;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description 原型模式
 * @Date 2021/7/11 23:22
 * @author: A.iguodala
 */
public class PrototypeTest {

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) throws Exception {
        UserService userService = new UserService();
        User user1 = userService.getUser("Aiguodala");
        user1.setUsername("nnzi");
        System.out.println("User 1 ==>" + user1);
        User user2 = userService.getUser("Aiguodala");
        System.out.println("User 2 ==>" + user2);
        User user3 = userService.getUser("Aiguodala");
        System.out.println("User 3 ==>" + user3);
        User user4 = userService.getUser("Aiguodala");
        System.out.println("User 4 ==>" + user4);

    }


}
class UserService {

    /**
     * 模拟缓存存储查询出的user信息
     */
    Map<String, User> cache = new ConcurrentHashMap<>();

    /**
     * 模拟注入UserMapper
     */
    UserMapper userMapper = new UserMapper();

    User getUser(String username) throws CloneNotSupportedException {
        if (cache.get(username) == null) {
            // 如果缓存中没有则去数据库查询
            User user = userMapper.getUser(username);
            // 将查出的对象克隆加入缓存,这样对其他线程对该对象的修改不会影响到缓存的值
            User cloneUser = (User) user.clone();
            // 将查询结果放入缓存
            cache.put(username, user);
            return cloneUser;
        }
        // 如果缓存中有,则直接克隆返回
        User cloneUser = (User) cache.get(username).clone();
        return cloneUser;
    }

}

/**
 * 模拟DAO层与数据库交互
 */
class UserMapper {

    /**
     * 模拟从数据库查询出User对象
     * @param username
     * @return
     */
    User getUser(String username) {
        return new User(username, "");
    }
}

/**
 * 模拟User实体对象
 */
@Data
@ToString
@AllArgsConstructor
class User implements Cloneable{
    String username;
    String password;

    /**
     * 实现克隆方法,通过原型创建一个克隆对象
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return new User(username, password);
    }
}

在这里插入图片描述
说明修改一个User对其他获取的对象不会造成影响,如果将克隆的方法去掉,直接使用缓存中的User,当某一个User改变用户名,则所有获取到该User的都会改变,可以自己尝试。

三、工厂模式

工厂模式(Factory Pattern)提供了一种创建对象的最佳方式。我们不必关心对象的创建细节,只需要根据不同情况获取不同产品即可

1. 简单工厂

简单工厂在于简单,直接通过传入的参数以及if判断或者swich判断来进行创建

示例:

/**
 * @Description
 * @Date 2021/7/11 23:46
 * @author: A.iguodala
 */
public class SimplyFactory {

    public static void main(String[] args) {
        Car benz = CarFactory.buildCar("Benz");
        benz.run();
        Car bwm = CarFactory.buildCar("BWM");
        bwm.run();
    }

}

/**
 * 汽车工厂
 */
class CarFactory {

    public static Car buildCar(String want) {

        // 通过if判断应该造哪种车
        // 这就是简单工厂
        if ("BWM".equals(want)) {
            return new BWM();
        }else if ("Benz".equals(want)) {
            return new Benz();
        }
        return null;
    }
}

/**
 * 汽车抽象类
 */
abstract class Car {
    /**
     * 汽车品牌
     */
    String brand;

    abstract void run();
}

/**
 * 汽车子类,宝马
 */
class BWM extends Car{

    @Override
    void run() {
        System.out.println("I am 宝马");
    }
}

/**
 * 汽车子类,奔驰
 */
class Benz extends Car {

    @Override
    void run() {
        System.out.println("I am 奔驰");
    }
}

缺点:

  • 如果有一万种车要造,要写一万个if,代码冗余
  • 如果新加了一辆车,那么需要修改源码,违反开闭原则,扩展困难

2. 工厂方法

定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。

例如,一个造车的工厂以及其子类具体到造哪一种车,如果需要哪一种车就到哪个特有的工厂去获取,而不是直接向父类的工厂获取,如果要新添加一种车,则只需要创建车和该车的工厂,不需要改动源码,符合开闭原则

在这里插入图片描述

/**
 * @Description
 * @Date 2021/7/12 14:18
 * @author: A.iguodala
 */
public class FactoryMethod {

    public static void main(String[] args) {
        /**
         * 把工厂抽象成父类,每个工厂生产不同的产品
         * 如果要添加产品,则只需要写该产品以及方法
         */
        CarFactory porscheFactory = new PorscheFactory();
        Car porsche = porscheFactory.getCar();
        porsche.run();

        CarFactory ferrariFactory = new FerrariFactory();
        Car ferrari = ferrariFactory.getCar();
        ferrari.run();
    }
}

/**
 * 抽象出的汽车
 */
abstract class Car {
    /**
     * 汽车品牌
     */
    String brand;

    /**
     * 开车方法
     */
    abstract void run();
}

class Porsche extends Car {

    @Override
    void run() {
        System.out.println("保时捷 run");
    }
}

class Ferrari extends Car {
    @Override
    void run() {
        System.out.println("法拉利 run");
    }
}

/**
 * 抽象出的汽车工厂
 */
abstract class CarFactory {

    /**
     * 汽车工厂有一个造出车的方法
     * @return
     */
    abstract Car buildCar();

    /**
     * 通过该方法获取车
     * @return
     */
    Car getCar () {
        Car car = buildCar();
        // 给Car做一些操作
        return car;
    }
}

class PorscheFactory extends CarFactory {

    @Override
    Car buildCar() {
        return new Porsche();
    }
}

class FerrariFactory extends CarFactory {

    @Override
    Car buildCar() {
        return new Ferrari();
    }
}

缺点:

  • 系统复杂,冗长,多了好多个类
  • 工厂职责单一,只能建造一种产品,例如,如果要让工厂造洗衣机,就只能改动抽象类工厂的代码,增加一个方法实现

2. 抽象工厂

抽象工厂就是对各个工厂在进行一个抽象,抽象一个总工厂,里面可以造各种产品,解决工厂方法产品单一的缺点,如果想要增加一个产品,则在总工厂中增加一个方法,然后有一个该产品的实现类工厂即可

在这里插入图片描述

/**
 * @Description
 * @Date 2021/7/12 15:06
 * @author: A.iguodala
 */
public class AbstractFactory {
    public static void main(String[] args) {
        GeneralFactory porscheFactory = new PorscheFactory();
        Car porsche = porscheFactory.getCar();
        porsche.run();

        GeneralFactory n95Factory = new N95MaskFactory();
        Mask n95 = n95Factory.getMask();
        n95.protect();
    }

}

/**
 * 抽象出的汽车
 */
abstract class Car {
    /**
     * 汽车品牌
     */
    String brand;

    /**
     * 开车方法
     */
    abstract void run();
}

class Porsche extends Car {

    @Override
    void run() {
        System.out.println("保时捷 run");
    }
}

class Ferrari extends Car {
    @Override
    void run() {
        System.out.println("法拉利 run");
    }
}

/**
 * 抽象出的口罩
 */
abstract class Mask {
    /**
     * 类型
     */
    String type;

    /**
     * 防护方法
     */
    abstract void protect();
}

class N95Mask extends Mask {
    @Override
    void protect() {
        System.out.println("N95口罩 防护");
    }
}

class SurgicalMask extends Mask {

    @Override
    void protect() {
        System.out.println("外科口罩 防护");
    }
}

/**
 * 抽象出的总工厂
 */
abstract class GeneralFactory {

    /**
     * 可以造车
     * @return
     */
    abstract Car getCar();

    /**
     * 也可以造口罩
     * @return
     */
    abstract Mask getMask();
}

/**
 * 抽象出的汽车工厂
 */
abstract class CarFactory extends GeneralFactory{

    /**
     * 汽车工厂有一个造出车的方法
     * @return
     */
    abstract Car buildCar();

    /**
     * 车工厂只实现总工厂的造车方法
     * @return
     */
    @Override
    Car getCar () {
        Car car = buildCar();
        // 给Car做一些操作
        return car;
    }

    @Override
    Mask getMask() {
        return null;
    }
}
class PorscheFactory extends CarFactory {

    @Override
    Car buildCar() {
        return new Porsche();
    }
}

class FerrariFactory extends CarFactory {

    @Override
    Car buildCar() {
        return new Ferrari();
    }
}

/**
 * 抽象出的口罩工厂
 */
abstract class MaskFactory extends GeneralFactory{
    /**
     * 子类继承造口罩的方法
     * @return
     */
    abstract Mask buildMask();

    @Override
    Mask getMask() {
        Mask mask = buildMask();
        return mask;
    }

    @Override
    Car getCar() {
        return null;
    }
}

class N95MaskFactory extends MaskFactory {

    @Override
    Mask buildMask() {
        return new N95Mask();
    }
}

class SurgicalMaskFactory extends MaskFactory {

    @Override
    Mask buildMask() {
        return new SurgicalMask();
    }
}

四、建造者模式

建造者模式封装建造对象的过程,但是并不屏蔽建造的细节

例如,建造一个手机,你不关心具体建造过程是什么样的,但是你关注内存,大小,颜色等等信息,这些信息由你提供

在这里插入图片描述

import lombok.Data;
import lombok.ToString;

/**
 * @Description
 * @Date 2021/7/12 16:14
 * @author: A.iguodala
 */
public class Builder {

    public static void main(String[] args) {
        AbstractPhoneBuilder huaweiBuilder = new HUAWEIBuilder();
        huaweiBuilder.diyColor("black");
        huaweiBuilder.diyMemory(128);
        huaweiBuilder.diySize("4寸");
        huaweiBuilder.diyCpuCore(8);
        Phone phone1 = huaweiBuilder.build();

        // 因为返回值是AbstractPhoneBuilder
        // 所以也可以链式调用
        Phone phone2 = new HUAWEIBuilder().diyColor("blue")
                .diyMemory(256)
                .diySize("5寸")
                .diyCpuCore(8)
                .build();

        System.out.println(phone1);
        System.out.println(phone2);
    }

}

/**
 * 建造的手机类
 */
@Data
@ToString
class Phone {
    private String color;
    private Integer memory;
    private String size;
    private Integer cpuCore;

}

/**
 * 抽象的手机建造者
 */
abstract class AbstractPhoneBuilder {
    /**
     * 建造的手机
     */
    protected Phone phone;

    /**
     * 可以自定义实现细节,
     * @param color
     * @return 返回值为AbstractPhoneBuilder则可以链式调用
     */
    abstract AbstractPhoneBuilder diyColor(String color);
    abstract AbstractPhoneBuilder diyMemory(Integer memory);
    abstract AbstractPhoneBuilder diySize(String size);
    abstract AbstractPhoneBuilder diyCpuCore(Integer cpuCore);

    /**
     * 将对象构造出来
     * @return
     */
    public Phone build() {
        return phone;
    }
}

/**
 * 华为建造者继承手机总建造者,自定义生产什么样的手机
 */
class HUAWEIBuilder extends AbstractPhoneBuilder {
    public HUAWEIBuilder() {
        phone = new Phone();
    }

    @Override
    AbstractPhoneBuilder diyColor(String color) {
        phone.setColor(color);
        return this;
    }

    @Override
    AbstractPhoneBuilder diyMemory(Integer memory) {
        phone.setMemory(memory);
        return this;
    }

    @Override
    AbstractPhoneBuilder diySize(String size) {
        phone.setSize(size);
        return this;
    }

    @Override
    AbstractPhoneBuilder diyCpuCore(Integer cpuCore) {
        phone.setCpuCore(cpuCore);
        return this;
    }
}

或者也可以改写成内部类的形式

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * @Description
 * @Date 2021/7/12 16:14
 * @author: A.iguodala
 */
public class Builder {

    public static void main(String[] args) {

        Phone phone = new Phone.Builder()
                .color("red")
                .memory(512)
                .size("3寸")
                .cpuCore(8)
                .build();
        System.out.println(phone);
    }

}

/**
 * 建造的手机类
 */
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
class Phone {
    private String color;
    private Integer memory;
    private String size;
    private Integer cpuCore;

    public static class Builder {
        private String color;
        private Integer memory;
        private String size;
        private Integer cpuCore;

        public Builder color(String color) {
            this.color = color;
            return this;
        }

        public Builder memory(Integer memory) {
            this.memory = memory;
            return this;
        }

        public Builder size(String size) {
            this.size = size;
            return this;
        }

        public Builder cpuCore(Integer cpuCore) {
            this.cpuCore = cpuCore;
            return this;
        }

        public Phone build() {
            return new Phone(color, memory, size, cpuCore);
        }
    }
}

总结:

  • 创建型的模式主要作用于对象的创建
  • 单例模式保证了线程安全以及全局只有一个该对象
  • 工厂模式屏蔽了创建对象的过程以及细节,只管从工厂获取对象,而建造者模式则屏蔽了创建的过程,没有屏蔽创建的细节,可以实现自己的定制化
  • 原型模式被Java原生支持,利用一个对象克隆出一个原型对象使用

之后我在别的地方看到设计模式的具体应用还会继续补充!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值