设计模式-创建型模式(详解)

设计模式之创建型模式详解

创建型模式

单例模式

一个类只允许创建一个对象,称为单例。

单例体现:配置类、连接池、全局计数器、id生成器、日志对象。

懒汉式
  1. (线程不安全) 单例:【不可用】

用到该单例对象的时候再创建。但存在很大问题,单线程下这段代码没有问题,但是在多线程下有很大问题。

public class LazyMan {
    private LazyMan(){};
    public static LazyMan lazyMan;   
    public static LazyMan getInstance(){
        if (lazyMan==null){
            lazyMan = new LazyMan();   //用到该单例对象的时候再创建,这里没加锁,如果多个线程进入,会并发产生多个实例
        }
        return lazyMan;
    }
}
  1. (线程安全)单例:【不推荐使用】

同步方法

缺点:效率低,每次getInstance时都要同步处理,存在性能问题,实际开发不推荐

public class LazyMan {
    private LazyMan(){};   //私有化构造函数,防止外部实例化
    public static LazyMan lazyMan;   
    public static synchroized LazyMan getInstance(){  //加锁
        if (lazyMan==null){
            lazyMan = new LazyMan();   //用到该单例对象的时候再创建
        }
        return lazyMan;
    }
}

双检锁(线程安全):【推荐使用】

  • 实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),不为空则直接return实例化对象。
  • 利用volatile关键字保证了可见性,利用双重检查机制减少了同步带来的性能损耗。
public class Singleton {
    private static volatile Singleton instance;
    // 私有构造函数,防止外部实例化
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
饿汉式

(静态常量)【可用】

类一旦加载就创建一个单例,保证在调用getInstance方法之前单例已经存在,即没有延迟加载,这种饿汉式单例会造成空间浪费。

public class Hungry {
    private Hungry(){}
    private final static Hungry HUNGRY = new Hungry();    //在类内部就创建了一个静态对象,并且get方法返回该对象
    public static Hungry getInstance(){
        return HUNGRY;
    }
}
//或者 静态代码块形式
public class Hungry {
  static{
    private final static Hungry HUNGRY = new Hungry();    
  }     
    private Hungry(){}
    public static Hungry getInstance(){
        return HUNGRY;
    }
}

Hungry in1=Hungry.getInstance()
Hungry in2=Hungry.getInstance()        //in1==in2
静态内部类
  • (线程安全)单例:【推荐使用】
  • 不仅线程安全,还实现了延迟加载
public class Inner {
    private Inner(){}
    //直到调用 getInstance() 方法之前,Inner 实例都不会被创建,实现了延迟初始化
    public static Inner getInstance(){
        return InnerClass.INNER;
    }
    private static class InnerClass{          
        private static final Inner INNER = new Inner();  //静态字段只会在类加载时被初始化一次,线程安全
    }
}
枚举
  • (线程安全)【推荐使用】不仅线程安全,还能防止反序列化导致重新创建新的对象
class SingletonEnum{
    // 1、创建一个枚举
    public enum CreateInstance{
        // 枚举实例,底层变量定义是public static final,因此它在 JVM 中只会被初始化一次,并且是线程安全的
        INSTANCE;
        private SingletonEnum instance;
        
        // 保证不能在类外部通过new构造器来构造对象
        private CreateInstance() {
            instance = new SingletonEnum();
            System.out.println(Thread.currentThread().getName());
        }
        // 创建一个公共的方法,由实例调用返回单例类
        public SingletonEnum getInstance() {
            return instance;
        }
    }
    public static void main(string[] args){
    	Singleton instance = CreateInstance.INSTANCE.getInstance();
    	singleton instance2= CreateInstance.INSTANCE.getInstance();
    	System.out.println(instance == instance2);  //输出 true
	}
}

原型模式

通过拷贝来创建新的对象,而不是通过实例化一个类,减少创建对象的成本,适用于创建对象成本高,需要大量相似对象的情况。

  • Java 的 clone 仅是浅拷贝,默写场景需要 使用深拷贝避免共享数据的导致错乱
  • 在 Spring 中,将 Bean 的作用范围设置为 prototype,这样每次从容器中获取 Bean 时,都会返回一个新的实例。

一个简单的原型模式实现例子如下

先创建一个原型类:

public class Prototype implements Cloneable {     //一个原型类,只需要实现Cloneable接口,覆写clone方法
	@Override
    public Object clone() throws CloneNotSupportedException { 
		Prototype proto = (Prototype) super.clone();		   //因为此处的重点是super.clone()这句话
		return proto;
	}
}
Prototype pro=new Prototype();
Prototype pro1=(Prototype)pro.clone(); //克隆 二者地址不同
//不管深浅,拷贝出来的对象的地址是不一样的,只是若对象里面有引用,那么深浅拷贝会不一样
@Data
public class Prototype implements Cloneable, Serializable {

	private static final long serialVersionUID = 1L;
	private String string;
	private SerializableObject obj;
	 
	/* 浅拷贝 */
	public Object clone() throws CloneNotSupportedException {
		Prototype proto = (Prototype) super.clone();
		return proto;
	}
	/* 深拷贝 */
	public Object deepClone() throws IOException, ClassNotFoundException {
		/* 写入当前对象的二进制流 */
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(this);
		/* 读出二进制流产生的新对象 */
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		return ois.readObject();
	}
	 
}
class SerializableObject implements Serializable {
	private static final long serialVersionUID = 1L;
}

工厂模式

简单工厂

简单工厂模式通过传入的不同的参数来控制创建哪个具体产品。它的实现较为简单,但不够灵活,违反了开放封闭原则。

  • 抽象产品接口: 定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品实现类: 实现或者继承抽象产品的子类
  • 简单工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。
// 产品接口
public interface Product {
    void use();
}
// 具体产品A
public class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}
// 具体产品B
public class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 简单工厂类
public class SimpleFactory {
    public static Product createProduct(String type) {
        switch (type) {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new IllegalArgumentException("Unknown product type");
        }
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.use(); // Output: Using ConcreteProductA

        Product productB = SimpleFactory.createProduct("B");
        productB.use(); // Output: Using ConcreteProductB
    }
}
工厂方法

一个具体的工厂类负责生产一种产品

抽象工厂==>具体工厂

抽象产品==>具体产品(由具体工厂创建)

// 抽象产品
interface Product {
    void use();
}
// 具体产品A
class ConcreteProductA implements Product {
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}
// 具体产品B
class ConcreteProductB implements Product {
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 抽象工厂
interface Factory {
    Product createProduct();
}
// 具体工厂A
class ConcreteFactoryA implements Factory {
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
// 具体工厂B
class ConcreteFactoryB implements Factory {
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 使用工厂方法创建产品
public class Client {
    public static void main(String[] args) {
        new ConcreteFactoryA().createProduct();
        new ConcreteFactoryB().createProduct() ;
    }
}
抽象工厂
  • 是工厂方法的一种变体,创建一系列相关或相互依赖对象的接口,即生产一系列产品
  • 给具体工厂类 添加一个工厂接口,使得工厂类可以多实现
// 抽象产品A
public interface ProductA {
    void use();
}
// 具体产品A1
public class ConcreteProductA1 implements ProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA1");
    }
}
// 具体产品A2
public class ConcreteProductA2 implements ProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA2");
    }
}

// 抽象产品B
public interface ProductB {
    void eat();
}
// 具体产品B1
public class ConcreteProductB1 implements ProductB {
    @Override
    public void eat() {
        System.out.println("Eating ConcreteProductB1");
    }
}
// 具体产品B2
public class ConcreteProductB2 implements ProductB {
    @Override
    public void eat() {
        System.out.println("Eating ConcreteProductB2");
    }
}

// 抽象工厂
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 使用抽象工厂创建产品
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.use();
        productB1.eat();

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.use();
        productB2.eat();
    }
}
建造者模式

建造者模式使用相同的代码基础构建不同类型的对象,通过将对象构建过程分解为多个较小的步骤来实现此目的,如StringBuilder

两个主要组成部分:建造者和产品 建造者是负责构建产品的类,产品则是最终构建的对象

例如 hutool 内的 ExecutorBuilder 就提供了建造者模式创建线程池的方法

public ExecutorService buildTaskPool() {
return ExecutorBuilder.create()
        .setCorePoolSize(10)
        .setMaxPoolSize(20)
        .setWorkQueue(new LinkedBlockingQueue<>(100))
        .setKeepAliveTime(3L, TimeUnit.SECONDS)
        .setThreadFactory(new ThreadFactoryBuilder().setNamePrefix("task-pool-").build())
        .build();
}
public class Product {       //最终构建的对象,即产品
    private String partA;
    private String partB;
    private String partC;
    public void setPartA(String partA) {
        this.partA = partA;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    } 
    public void setPartC(String partC) {
        this.partC = partC;
    }
    // other product-related methods

}

public interface Builder {   //Builder接口或抽象类,定义了构建过程的关键步骤
    void buildPartA();
    void buildPartB();
    void buildPartC();
    Product getResult();
}
  
public class ConcreteBuilder implements Builder {  //实现了Builder接口中定义的方法,以构建具体的Product对象
    private Product product = new Product();
    public void buildPartA() {
        product.setPartA("Part A");
    }
    public void buildPartB() {
        product.setPartB("Part B");
    }
    public void buildPartC() {
        product.setPartC("Part C");
    }    
    public Product getResult() {
        return product;
    } 
}

public class Director {      //指导类,它负责使用Builder对象来构建最终的Product对象
    private Builder builder;

    public Director(Builder builder) {  //实现依赖倒置原则,依赖于抽象
        this.builder = builder; 
    }
    public void construct() {   //确保Product对象按照指定的顺序创建
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
    }
}

Builder builder = new ConcreteBuilder();   //创建建造者
Director director = new Director(builder);  //创建指导
director.construct();     
Product product = builder.getResult();
//这将构建一个Product对象,并将其存储在product变量中。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

空说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值