学点设计模式,盘点Spring等源码中与设计模式的那些事之创建型模型

学点设计模式,盘点Spring等源码中与设计模式的那些事之创建型模型

首先,在创建型模式中,包括了以下几种设计模式:

  • 单例模式
  • 原型模式
  • 工厂方法模式
  • 抽象工厂模式
  • 建造者模式

为什么会有创建型模式,它有什么用呢?

  • 创建型模式主要关注怎样创建出对象将对象的创建和使用分离
  • 它能降低系统的耦合度使用者无需关注对象的创建细节

1、单例模式

  • 定义:一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。
  • 特点 —— 做法:
    • 这个类只能有一个实例 —— 构造器私有
    • 必须自行创建这个实例 —— 自己编写实例化逻辑
    • 想整个系统提供这个实例 —— 对外提供实例方法

关于单例模式的实现,本专栏专门有一篇文章讲解单例模式常见的七种写法,这里就不再附代码了,点击查看

  • 使用场景
    • 1、多线程中的线程池、数据库连接池等池化操作
    • 2、系统环境信息,如Java中的System类获取当前系统属性、环境变量等

2、原型模式

  • 定义:用于创建重复的对象,同时又能保证性能
  • 举个栗子:比如我们现在要写一个查询数据库的框架MeBatis,数据库中的数据基本不会改变,每次查询到之后,把查到的所有数据封装成一个对象返回。试想一下,如果现在有10000个线程在查询相同的一个记录,那么,就会创建出10000个这样的对象,造成极大的浪费。
  • 解决例子的问题:对于上边的问题,我们可以想到,将第一次查询到的数据缓存到一个Map中,以后每次查询先去Map中看有没有,有的话直接返回,没有再查询数据库。
  • 存在问题:这样的方案仔细想想还是有问题的,如果其中的一个线程获取对象之后,将这个对象修改了,那么,后边所有的线程都将拿到一个错误的数据,造成脏缓存问题。
  • 怎么办呢:这时候就可以考虑原型模式,当线程拿到数据对象之后,我们不直接返回,而是返回一个克隆对象,那么无论这个线程如何修改,都不会影响缓存数据,后边的线程就会获取到正确的数据
  • 代码演示:10000个线程查询数据库中一个User数据(模拟,部分主要代码)
//User:实现Cloneable接口,重写clone()方法
public class User implements Cloneable {

    private String username;
    private Integer age;

    /**
     * 再创建一个人,赋予我的所有属性
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user = new User();
        user.setUsername(username);
        user.setAge(age);
        return user;
    }
}
public class Mebatis {
    //缓存user
    private Map<String,User> userCache = new HashMap<>();

    //模拟从数据库查数据
    public User getUser(String username) throws Exception {
        User user = null;
        //缓存中没有
        if(!userCache.containsKey(username)){
            //查询数据库
            user = getUserFromDb(username);
        }else {
            //从缓存中直接拿,脏缓存问题
            //原型已经拿到,但是不能直接给。
            user = userCache.get(username);
            System.out.println("从缓存中拿到的是:"+user);
            //从这个对象快速得到一个克隆体(克隆人)==原型模式
            user = (User) user.clone();
        }
        return user;
    }

    private User getUserFromDb(String username) throws Exception{
        System.out.println("从数据库查到:"+username);
        User user = new User();
        user.setUsername(username);
        user.setAge(18);
        //给缓存中放一个clone
        userCache.put(username, (User) user.clone());
        return user;
    }
}
  • 总结:本体给外部提供一个克隆体使用

3、工厂模式

  • 定义:提供一种创建对象的最佳方式,使我们不必关系创建细节,只需根据不同情况获得不同产品
1.简单工厂
  • 在只有几个产品的情况下,适合使用简单工厂模式,比如现在有一个汽车工厂,只生产两种车
    在这里插入图片描述
  • 代码示例:
/**
 * 简单工厂
 * 1、产品数量极少
 */
public class WuLinSimpleFactory {
    
    public AbstractCar newCar(String type){

        //核心方法:一切从简
        if("van".equals(type)){
            // 钣金、喷漆、放发动机、申请环保
            return new VanCar();
        }else if("mini".equals(type)){
            return new MiniCar();
        }
        return null;//没有产品
    }
}
/**
 * 抽象的产品
 */
public abstract class AbstractCar {

    String engine;
    public abstract void run();
}
//具体产品
public class MiniCar extends AbstractCar{

    public MiniCar(){
        this.engine = "单引擎";
    }
    @Override
    public void run() {
        System.out.println(engine+"--> 发车...");
    }
}

/**
 * 具体产品
 */
public class VanCar extends AbstractCar{
    public VanCar(){
        this.engine = "双引擎";
    }
    @Override
    public void run() {
        System.out.println(engine+"-->发车");
    }
}
  • 缺点:扩产性差,违反开闭原则
2.工厂方法
  • 改进:将工厂提升一个等级,创建一个抽象的工厂,然后利用多个具体的工厂,每个工厂生产一种商品,想要扩展产品时,只需要添加具体的工厂,提高程序的可扩展性。
    在这里插入图片描述
  • 主要代码:
/**
 * 抽象工厂
 */
public abstract class AbstractCarFactory {

    public abstract AbstractCar newCar();
    //我能造什么.....
}

/**
 * minicar分厂,具体的产品工厂,可以扩展添加
 */
public class WulinMinCarFactory extends AbstractCarFactory{
    @Override
    public AbstractCar newCar() {
        return new MiniCar();
    }
}
//具体的产品,有某一具体的工厂生产
public class MiniCar extends AbstractCar {
    
    public MiniCar(){
        this.engine = "迷你发动机";
    }
    @Override
    public void run() {
        System.out.println(engine+"--> 发车...");
    }
}
  • 缺点:品类单一,现在只能造车,我要是想造口罩怎么办
3.抽象工厂
  • 改进:为了满足多个产品,继续向上抽象
    在这里插入图片描述
  • 主要代码
/**
 * 总集团规范,最上层抽象工厂,定义可以造啥
 */
public abstract class WulinFactory {

    abstract AbstractCar newCar();
    abstract AbstractMask newMask();
}
/**
 * wulin 汽车子集团,只负责造汽车,口罩直接返回null
 */
public  abstract  class WulinCarFactory extends WulinFactory{
    @Override
    abstract  AbstractCar newCar();

    @Override
    AbstractMask newMask() {
        return null;
    }
}

/**
 * wulin口罩子集团,只负责造口罩,汽车直接返回null
 */
public abstract class WulinMaskFactory extends WulinFactory{
    @Override
    AbstractCar newCar() {
        return null;
    }

    abstract AbstractMask newMask();
}
/**
 * 抽象产品
 */
public abstract class AbstractCar {

    String engine;
    public abstract void run();
}

/**
 * 抽象产品
 */
public abstract class AbstractMask {

    Integer price;
    public abstract void protectedMe();
}
//具体产品省略,代码太多了......
/**
 * 口罩子集团建分厂:只造口罩,且武汉的厂只造N95口罩
 */
public class WulinWuHanMaskFactory  extends WulinMaskFactory{

    @Override
    AbstractMask newMask() {
        return new N95Mask();
    }
}

/**
 * 口罩子集团建分厂:只造口罩,且杭州的厂造普通外科口罩
 */
public class WulinHangZhouMaskFactory extends WulinMaskFactory {

    @Override
    AbstractMask newMask() {
        return new CommonMask();
    }
}
//汽车子集团建汽车各地分厂类似......

4、建造者模式

  • 定义:创建的东西细节复杂,还必须暴露给使用者。屏蔽过程而不屏蔽细节
  • 举例(比如我们现在要定制一台手机)
//我们想要定制的手机
@Getter
@ToString
public class Phone {

    protected String cpu;
    protected String mem;
    protected String disk;
    protected String cam;
}

/**
 * 抽象建造者,定义我们定制化的参数,返回最终的手机
 */
public abstract class AbstractBuilder  {

    Phone phone;
    abstract AbstractBuilder customCpu(String cpu);
    abstract AbstractBuilder customMem(String mem);
    abstract AbstractBuilder customDisk(String disk);
    abstract AbstractBuilder customCam(String cam);

    Phone getProduct(){
        return phone;
    }
}

//赋值后返回自己,方便链式调用
public class XiaomiBuilder  extends AbstractBuilder{
    public XiaomiBuilder(){
        phone = new Phone();
    }
    
    @Override
    AbstractBuilder customCpu(String cpu) {
        phone.cpu = cpu;
        return this;
    }

    @Override
    AbstractBuilder customMem(String mem) {
        phone.mem = mem;
        return this;
    }

    @Override
    AbstractBuilder customDisk(String disk) {
        phone.disk = disk;
        return this;
    }

    @Override
    AbstractBuilder customCam(String cam) {
        phone.cam = cam;
        return this;
    }
}

到这里,创建型的几种设计模式就学习完了,下一篇结构型设计模式…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anton丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值