创建型模式

1. 单例模式*

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点

单例模式使用的场景:需要频繁创建和销毁或创建时耗费资源过多,但又经常用到的对象

1.1 饿汉式(静态常量)

java.lang.Runtime就采用了饿汉式单例模式

饿汉式(静态常量/静态代码块):

  1. 优点:这种方式基于classloder机制,在类加载时就完成了单例的实例化,避免了线程同步问题
  2. 缺点:如果从始至终从未使用过这个实例,则会造成内存的浪费

// 饿汉式(静态常量)
public class Singleton {
    // 在自己内部定义一个自己的实例
    private final static Singleton INSTANCE = new Singleton();

    // 私有构造方法(防止new)
    private Singleton() {
    }

    // 提供一个供外部获取对象的静态公共方法
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

1.2 饿汉式(静态代码块)

// 饿汉式(静态代码块)
public class Singleton {
    private static Singleton instance;

    // 在类加载时,创建单例实例
    static {
        instance = new Singleton();
    }

    // 私有构造方法(防止new)
    private Singleton() {
    }

    // 提供一个供外部获取对象的静态公共方法
    public static Singleton getInstance() {
        return instance;
    }
}

1.3 懒汉式(线程安全,同步方法)-

懒汉式:全局的单例实例在需要时再构建(不推荐)

// 懒汉式(线程安全,同步方法)
public class Singleton {
    // 在自己内部定义一个自己的实例
    private static Singleton instance;

    // 私有构造方法(防止new)
    private Singleton() {
    }

    // 提供一个供外部获取对象的静态公共方法,当第一次使用该方法时,再去创建单例实例
    // 同步效率太低:每个线程在执行getInstance()时都要同步,
    // 但getInstance()只需在第一次使用创建单例对象时需要同步
    public static synchronized Singleton getInstance() {
        // 避免了多线程时,一个线程进入了if (instance == null),
        // 还未来得及往下执行,另一个线程也通过了这个判断语句而产生多个实例
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

1.4 双重检查

// 双重检查
public class Singleton {
    // 在自己内部定义一个自己的实例
    // 使用volatile防止创建对象时的重排序
    private static volatile Singleton instance;

    // 私有构造方法(防止new)
    private Singleton() {
        // 以双重检查为例,防止暴力反射破解单例模式
        if (instance != null)
            throw new RuntimeException("防止暴力反射破解单例模式");
    }

    // 提供一个供外部获取对象的静态公共方法
    // 使用双重检查,解决了线程安全问题和懒加载问题
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

1.5 静态内部类

// 静态内部类
public class Singleton {
    // 在静态内部类中创建单例实例:在第一次使用到SingletonInstance类时,才会加载该类
    // 解决了线程安全问题和懒加载问题
    private static class SingletonInstance {
        private final static Singleton INSTANCE = new Singleton();
    }

    // 私有构造方法(防止new)
    private Singleton() {
    }

    // 提供一个供外部获取对象的静态公共方法
    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

1.6 枚举

// 枚举:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton {
    INSTANCE;

    public void method() {
        System.out.println("枚举实现单例模式");
    }
}

class SingletonClient {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1 == singleton2);
        singleton1.method();
        /**
         * 结果:
         * true
         * 枚举实现单例模式
         */
    }
}

2. 工厂方法模式*

2.1 简单工厂模式

简单工厂模式又叫做静态工厂方法模式,但不属于23种设计模式之一

简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例

由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,因此一般只在工厂类负责创建的对象比较少的情况下应用

java.util.Calendar类就使用了简单工厂模式

// 抽象产品
interface Animal {
}

// 具体产品
class Dog implements Animal {
}

// 具体工厂:简单工厂模式的核心
class AnimalFactory {
    public static Animal createAnimal(String type) {
        switch (type) {
            case "Dog":
                return new Dog();
            default:
                return null;
        }
    }
}

public class StaticFactoryMethodClient {
    public static void main(String[] args) {
        Animal dog = AnimalFactory.createAnimal("Dog");
        // true
        System.out.println(dog instanceof Dog);
    }
}

2.2 工厂方法模式

工厂方法模式的意义:定义一个用于创建对象的接口,让子类决定实例化哪一个类

工厂方法模式中存在四种角色:

  1. 抽象产品:产品对象的共同父类或共同拥有的接口
  2. 具体产品:这个角色实现了抽象产品角色所定义的接口
  3. 抽象工厂:任何在模式中创建对象的工厂类必须实现这个接口
  4. 具体工厂:实现抽象工厂接口的具体工厂类

工厂方法模式是模板方法模式的应用

// 抽象产品
interface Animal {
}

// 具体产品
class Dog implements Animal {
}

// 抽象工厂:工厂方法模式的核心
interface AnimalFactory {
    Animal createAnimal();
}

// 具体工厂
class DogFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}

public class FactoryMethodClient {
    public static void main(String[] args) {
        DogFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        // true
        System.out.println(dog instanceof Dog);
    }
}

3. 抽象工厂模式

抽象工厂模式:提供一个接口以创建一系列相关或相互依赖的对象,而无须指定它们具体的类

工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类

抽象工厂模式解决的问题是当涉及到有多个产品等级结构时,如何更好地进行软件体系结构的设计

// 抽象产品:动物
interface Animal {
}

// 抽象产品:植物
interface Plant {
}

// 具体产品:中国动物
class ChinaAnimal implements Animal {
}

// 具体产品:中国植物
class ChinaPlant implements Plant {
}

// 具体产品:美国动物
class AmericaAnimal implements Animal {
}

// 具体产品:美国植物
class AmericaPlant implements Plant {
}

// 抽象工厂:抽象工厂模式的核心
interface Factory {
    Animal createAnimal();

    Plant createPlant();
}

// 具体工厂:中国工厂
class ChinaFactory implements Factory {
    @Override
    public Animal createAnimal() {
        return new ChinaAnimal();
    }

    @Override
    public Plant createPlant() {
        return new ChinaPlant();
    }
}

// 具体工厂:美国工厂
class AmericaFactory implements Factory {
    @Override
    public Animal createAnimal() {
        return new AmericaAnimal();
    }

    @Override
    public Plant createPlant() {
        return new AmericaPlant();
    }
}

public class AbstractFactoryClient {
    public static void main(String[] args) {
        Factory chinaFactory = new ChinaFactory();
        Factory americaFactory = new AmericaFactory();
        System.out.println(chinaFactory.createAnimal() instanceof ChinaAnimal);
        System.out.println(chinaFactory.createPlant() instanceof ChinaPlant);
        System.out.println(americaFactory.createAnimal() instanceof AmericaAnimal);
        System.out.println(americaFactory.createPlant() instanceof AmericaPlant);
    }
}

4. 原型模式

原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

原型模式主要解决的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口

缺点:需要给类配备一个克隆方法,对已有的类需要修改其源代码,违背了开闭原则

原型模式:在原型中自带一个拷贝方法

import lombok.Data;

import java.io.Serializable;

// 重写Object的clone()方法需要实现Cloneable接口
@Data
public class Prototype implements Serializable, Cloneable {
    String attribute;

    // 默认super.clone()浅拷贝:对象中的值类型成员变量拷贝值,引用类型成员变量仅拷贝引用
    @Override
    protected Object clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

深拷贝:

import lombok.Data;

import java.io.*;

@Data
public class DeepCopy implements Serializable, Cloneable {
    String value;
    Prototype prototype;

    // 重写clone()深拷贝:对象中的值类型成员变量拷贝值,引用类型成员变量拷贝整个引用对象
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = null;
        // 对值类型进行拷贝
        obj = super.clone();
        // 对引用类型进行拷贝
        ((DeepCopy) obj).prototype = (Prototype) prototype.clone();
        return obj;
    }

    // 对象序列化深拷贝*:对象中的值类型成员变量拷贝值,引用类型成员变量拷贝整个引用对象
    public Object deepCloneBySerializable() {
        Object obj = null;
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            // 反序列化
            bais = new ByteArrayInputStream(baos.toByteArray());
            ois = new ObjectInputStream(bais);
            obj = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bais.close();
                ois.close();
                baos.close();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return obj;
    }
}

5. 建造者模式*

建造者模式(生成器模式):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

建造者模式中有以下几个角色:

  1. 产品Product:表示被构造的复杂对象
  2. 抽象建造者Builder:为创建一个产品对象的各个部件指定抽象接口
  3. 具体建造者ConcreteBuilder:实现Builder的接口,构造和装配该产品的各个部件
  4. 指导者Director:构造一个使用Builder接口的对象,它负责控制产品对象的生产过程,隔离了客户与对象的生产过程

建造者模式在使用过程中可以演化出多种形式,如:

  1. 省略抽象建造者角色
  2. 省略指导者角色

java.lang.StringBuilder的append方法使用的就是建造者模式

import lombok.Data;

// 产品
@Data
class Product {
    String inner;
    String outer;
}

// 抽象建造者:抽象出建造过程
interface Builder {
    void buildInner();

    void buildOuter();

    Product buildProduct();
}

// 具体建造者:不同产品,创建不同的具体建造者
class ConcreteBuilder implements Builder {
    Product product;

    public ConcreteBuilder(Product product) {
        this.product = product;
    }

    @Override
    public void buildInner() {
        product.inner = "建造产品内部";
    }

    @Override
    public void buildOuter() {
        product.outer = "建造产品外部";
    }

    @Override
    public Product buildProduct() {
        return product;
    }
}

// 指导者:根据建造过程组装产品
class Director {
    public Product constructProduct(Builder builder) {
        builder.buildInner();
        builder.buildOuter();
        return builder.buildProduct();
    }
}

public class BuilderClient {
    public static void main(String[] args) {
        ConcreteBuilder concreteBuilder = new ConcreteBuilder(new Product());
        Director director = new Director();
        Product product = director.constructProduct(concreteBuilder);
        // Product(inner=建造产品内部, outer=建造产品外部)
        System.out.println(product);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值