设计模式上篇-创建型

经典设计模式有23个,分为创建型,结构型和行为型。

创建型主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。

创建型的设计模式有工厂模式,抽象工厂模式,单例模式,建造者模式和原型模式。

工厂模式-Factory

简单工厂

package cn.hgy.simplefactory;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class SimpleFactory {

    public BaseClass getClass(String type) {
        String classAType = "classA";
        if (classAType.equals(type)) {
            return new ClassA();
        } else {
            return new ClassB();
        }
    }
}

如果要增加类型,需要更新工厂代码,不符合开闭原则。解决方案如下:

工厂模式

工厂接口


package cn.hgy.factory;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public abstract class BaseFactory {

    protected abstract boolean handle(String type);

    public abstract BaseClass create();
}

工厂接口实现

package cn.hgy.factory;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class ClassAFactory extends BaseFactory {

    private static final String CLASS_A_TYPE = "classA";

    @Override
    public boolean handle(String type) {
        return CLASS_A_TYPE.equals(type);
    }

    @Override
    public BaseClass create() {
        return new ClassA();
    }
}

工厂类

package cn.hgy.factory;


import java.io.File;
import java.util.*;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class Factory {

    public BaseClass getClass(String type) {

        List<BaseFactory> factoryList = getAllClass();
        for(BaseFactory baseFactory : factoryList) {
            if(baseFactory.handle(type)){
                return baseFactory.create();
            }
        }
        return null;
    }

    /**
     * 根据反射获取所有的工厂类
     * @return
     */
    private List<BaseFactory> getAllClass(){
        File directory = new File("D:\\codespace\\design-pattern-study\\factory\\target\\classes\\cn\\hgy\\factory");
        File[] files = directory.listFiles();

        List<BaseFactory> factoryList = new ArrayList<>();
        for (File file : files) {
            String filePath = file.getPath().replace("D:\\codespace\\design-pattern-study\\factory\\target\\classes\\", "");
            filePath = filePath.replaceAll(".class", "");
            filePath = filePath.replaceAll("\\\\", ".");

            try {
                Class clazz = Class.forName(filePath);
                if(clazz.getSuperclass() != null && clazz.getSuperclass().equals(BaseFactory.class)){
                    BaseFactory factory = (BaseFactory)Class.forName(filePath).newInstance();
                    factoryList.add(factory);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return factoryList;
    }
}

如果使用spring,做法则更简单,代码如下:


@Component
public class ClassAFactory extends BaseFactory {
    // something
}


/**
 * @author guoyu.huang
 * @version 1.0.0
 */
@Component
public class Factory {

    @Autowired
    private List<BaseFactory> factoryList;

    public BaseClass getClass(String type) {

        for(BaseFactory baseFactory : factoryList) {
            if(baseFactory.handle(type)){
                return baseFactory.create();
            }
        }
        return null;
    }
}

使用工厂实现简单spring工厂,参考地址:https://github.com/CNXMBuyu/design-pattern-study.git

抽象工厂

抽象工厂可以理解是工厂的工厂,将同一类型的工厂抽象成一个工厂类,用于大型的创建对象。

单例模式 - Singleton

单例模式不再过多描述,直接上例子。

饿汉式

package cn.hgy.single.eager;

/**
 * 饿汉单例模式,先实例化
 *
 * @author guoyu.huang
 * @version 1.0.0
 */
public class EagerSingleton {

    private static EagerSingleton eagerSingleton = new EagerSingleton();

    private EagerSingleton(){

    }

    public static EagerSingleton getInstance(){
        return eagerSingleton;
    }
}

懒汉式

package cn.hgy.single.lazy;

/**
 * 懒汉单例模式,需要的时候实例化
 *
 * @author guoyu.huang
 * @version 1.0.0
 */
public class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            return new LazySingleton();
        } else {
            return instance;
        }
    }
}

双重校验

package cn.hgy.single.doublecheck;

/**
 * 双重校验单例模式
 *
 * @author guoyu.huang
 * @version 1.0.0
 */
public class DoubleCheckSingleton {

    private static volatile DoubleCheckSingleton instance;

    private DoubleCheckSingleton() {
    }

    public static DoubleCheckSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckSingleton.class) {
                instance = new DoubleCheckSingleton();

            }
        }
        return instance;
    }
}

内部类

效果等同于双重校验

package cn.hgy.single.inner;

import cn.hgy.single.doublecheck.DoubleCheckSingleton;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class InnerSingleton {

    private InnerSingleton(){}

    public static InnerSingleton getInstance() {
        return Singleton.instance;
    }

    private static class Singleton{
        private static final InnerSingleton instance = new InnerSingleton();
    }
}

建造者-Builder

建造者一般是当构造函数或者set函数无法满足。例如构造函数中参数超过5个,易用性很低;属性之间互相依赖,无法通过set函数来进行逻辑校验。可以考虑建造者模式

package cn.hgy.builder;

/**
 * 建造者模式
 *
 * @author guoyu.huang
 * @version 1.0.0
 */
public class BuilderClass {

    private String a;
    private String b;
    private String c;
    private String d;

    private BuilderClass(Builder builder) {
        this.a = builder.a;
        this.b = builder.b;
        this.c = builder.c;
        this.d = builder.d;
    }

    public static class Builder {
        private String a;
        private String b;
        private String c;
        private String d;

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

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

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

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

        public BuilderClass build() {
            if (this.a.equals(b)) {
                throw new IllegalArgumentException("a不能和b属性一样");
            }
            return new BuilderClass(this);
        }
    }
}

原型模式-Prototype

原型模式就是利用对已有对象(原型)进行复制(或者叫拷贝)的方式,来创建新对象,以达到节省创建时间的目的。

浅拷贝

对象中除了基本类型,引用类型的地址还是指向原对象的地址,所以原对象的属性变更会对其产生印象。

package cn.hgy.prototype;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class Shallow {

    private List<ClassA> list;

    public Shallow(List<ClassA> list){
        this.list = Arrays.asList(list.toArray(new ClassA[list.size()]).clone());
    }

    public List<ClassA> getList() {
        return list;
    }

}

深拷贝

对象中所有属性都是全新的地址,互不干扰。

package cn.hgy.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class Deep {

    private List<ClassA> list;

    public Deep(List<ClassA> list){
        this.list = new ArrayList<>(list.size());
        list.forEach(classA -> {
            this.list.add(deepCopy(classA));
        });
    }
    
    public List<ClassA> getList() {
        return list;
    }

    public ClassA deepCopy(ClassA object) {
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(object);

            ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
            ObjectInputStream oi = new ObjectInputStream(bi);
            return (ClassA) oi.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

通用类

package cn.hgy.prototype;

import java.io.Serializable;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class ClassA implements Serializable {

    private String a;
    private String b;

    public ClassA(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "ClassA{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }

}

package cn.hgy.prototype;

import java.util.ArrayList;
import java.util.List;

/**
 * @author guoyu.huang
 * @version 1.0.0
 */
public class Prototype {

    public static void main(String[] args) {

        List<ClassA> list = new ArrayList<>();
        list.add(new ClassA("a1", "b1"));
        list.add(new ClassA("a2", "b2"));

        List<ClassA> shallow = new Shallow(list).getList();
        List<ClassA> deep = new Deep(list).getList();


        list.get(0).setA("new a1");

        System.out.println("shallow foreach");
        shallow.forEach(classA -> {
            System.out.println(classA.toString());
        });

        System.out.println("deep foreach");
        deep.forEach(classA -> {
            System.out.println(classA.toString());
        });
    }
    
}

// 打印信息如下:
shallow foreach
ClassA{a='new a1', b='b1'}
ClassA{a='a2', b='b2'}
deep foreach
ClassA{a='a1', b='b1'}
ClassA{a='a2', b='b2'}

总结

创建型设计模式主要是为了解决对象创建问题,当对象的创建通过简单的构造函数实现时,可以考虑创建型设计模式的思路。

  • 工厂模式

当对象创建逻辑比较复杂时,可能会有很多的if-else判断时,可以考虑工厂模式。

工厂模式有简单工厂,工厂和抽象工厂。

  • 单例模式

当为了防止资源访问冲突时,可以将该资源的访问类设置为单例模式。

单例模式有懒汉式(延迟加载),饿汉式(事先加载),双重校验(懒汉式同步锁加载),内部类(依赖java加载类的特性来事先懒汉式加载)。

  • 建造者模式

当一个类的必填属性过多,使用构造函数易用性大大降低,且属性之间有依赖关系,无法通过set函数来控制时,可以考虑建造者模式。

建造者模式会将必填项通过建造者模式类的set函数进行赋值,在实例化具体的类之前,可以编写业务逻辑来进行业务逻辑校验。

  • 原型模式

当有大量已存在的对象要额外复制一份时,可以考虑使用原型模式。

原型模式的实现方式有浅拷贝和深拷贝。浅拷贝的对象引用类型的属性指向原对象的地址,s会互相影响;深拷贝的对象引用类型的属性都是全新的地址,互不影响。

关注我

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

瑾析编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值