工厂模式和单例模式的学习

单例模式

概念:

1.一个类只有一个实例,并提供一个全局访问点
2.提供静态的getInstance()工厂方法用来访问它的唯一实例
3.为了防止其它外部对他实例化,所以构造函数私有

作用:

1.控制实例数目节省系统资源
2.可以在不建立直接关联的条件下, 让多个不相关的两个线程或者进程之间实现通信(作为通信媒介)

应用场景:

一个全局使用的类频繁的创建与销毁,eg:
1.网站计数器
2.windows系统的任务管理器和回收站
3.一般池的设计都是单例模式,例如数据库连接池和多线程连接池,可以降低资源的消耗

代码示例:

饿汉式单例:

饿汉式单例在类加载时就创建了单例实例,不管之后是否会使用这个实例。由于实例在类加载时就已经创建好,所以它是线程安全的,因为类加载过程是由 JVM 保证线程安全的

public class EagerSingleton {
    // 在类加载时就创建单例实例
    private static final EagerSingleton INSTANCE = new EagerSingleton();

    // 私有构造函数,防止外部实例化
    private EagerSingleton() {}

    // 提供公共的静态方法来获取单例实例
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }

    public void doSomething() {
        System.out.println("EagerSingleton is doing something.");
    }

    public static void main(String[] args) {
        EagerSingleton singleton = EagerSingleton.getInstance();
        singleton.doSomething();
    }
}

适用于实例创建成本较低且需要保证线程安全的场景

懒汉式单例:

懒汉式单例在第一次使用时才创建实例,也就是在调用获取实例的方法时才进行实例化
但如果不进行适当的同步处理,懒汉式单例在多线程环境下可能会出现线程安全问题

非线程安全:
public class LazySingleton {
    private static LazySingleton INSTANCE;

    private LazySingleton() {}

    // 非线程安全的获取实例方法
    public static LazySingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }

    public void doSomething() {
        System.out.println("LazySingleton is doing something.");
    }

    public static void main(String[] args) {
        LazySingleton singleton = LazySingleton.getInstance();
        singleton.doSomething();
    }
}

在 getInstance() 方法中,首先检查实例是否为 null,如果为 null 则创建实例。但在多线程环境下,可能会有多个线程同时进入 if (INSTANCE == null) 语句块,从而创建多个实例

线程安全:
// 线程安全的懒汉式单例(双重检查锁定)
public class ThreadSafeLazySingleton {
    // 使用 volatile 关键字确保可见性
    private static volatile ThreadSafeLazySingleton INSTANCE;

    private ThreadSafeLazySingleton() {}

    // 线程安全的获取实例方法
    public static ThreadSafeLazySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (ThreadSafeLazySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new ThreadSafeLazySingleton();
                }
            }  
        }
        return INSTANCE;
    }

    public void doSomething() {
        System.out.println("ThreadSafeLazySingleton is doing something.");
    }

    public static void main(String[] args) {
        ThreadSafeLazySingleton singleton = ThreadSafeLazySingleton.getInstance();
        singleton.doSomething();
    }
}

使用 volatile 关键字确保 INSTANCE 变量的可见性,在 getInstance() 方法中进行双重检查。首先检查实例是否为 null,如果为 null 则进入同步块,在同步块中再次检查实例是否为 null,如果仍然为 null 则创建实例。这样可以避免在多线程环境下创建多个实例

工厂模式

概念:

实例化对象不使用new,而是使用工厂方法代替,提供了一种创建对象的最佳方式
并且工厂模式中,创建对象的逻辑是不会向客户端暴露的,且通过使用一个共同的接口来指向创建的对象

代码示例:

简单工厂模式

也叫做静态工厂模式,是工厂模式的基础,它定义了一个工厂类,负责根据不同的条件创建不同类型的产品对象。简单工厂模式通常包含一个工厂类、一个抽象产品类和多个具体产品类

// 抽象产品类
interface Product {
    void use();
}

// 具体产品类 A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}

// 具体产品类 B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        return null;
    }
}

// 客户端代码
public class SimpleFactoryClient {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        if (productA != null) {
            productA.use();
        }
        Product productB = SimpleFactory.createProduct("B");
        if (productB != null) {
            productB.use();
        }
    }
}

可以理解为不再使用new创建实例,而是使用函数代替,其实这也间接体现的java的封装特性
代码解释:
● Product 是抽象产品类,定义了产品的通用方法 use()
● ConcreteProductA 和 ConcreteProductB 是具体产品类,实现了 Product 接口
● SimpleFactory 是简单工厂类,根据传入的参数 type 来创建不同类型的产品对象
● 客户端代码通过调用 SimpleFactory 的 createProduct() 方法来获取产品对象

工厂方法模式:

工厂方法模式将对象的创建延迟到子类中进行,定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式包含一个抽象工厂类、多个具体工厂类、一个抽象产品类和多个具体产品类

// 抽象产品类
interface Product {
    void use();
}

// 具体产品类 A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}

// 具体产品类 B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 抽象工厂类
abstract class Factory {
    public abstract Product createProduct();
}

// 具体工厂类 A,负责创建产品 A
class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂类 B,负责创建产品 B
class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端代码
public class FactoryMethodClient {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.use();

        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.use();
    }
}

和简单工厂对比就是多添加了一步实现抽象工厂类的过程,让子类决定实例化哪一个类, 工厂方法把实例化的权利交给了子类
代码解释:
● Product 是抽象产品类,定义了产品的通用方法 use()
● ConcreteProductA 和 ConcreteProductB 是具体产品类,实现了 Product 接口
● Factory 是抽象工厂类,定义了一个抽象方法 createProduct() 用于创建产品对象
● ConcreteFactoryA 和 ConcreteFactoryB 是具体工厂类,分别实现了 createProduct() 方法,负责创建具体的产品对象
● 客户端代码通过创建具体的工厂类对象,调用其 createProduct() 方法来获取产品对象

抽象工厂模式

上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品, 如果要生成另一类产品那应该如何表示?
这时候我们就需要用到抽象工厂模式

// 抽象产品类 A
interface ProductA {
    void use();
}

// 具体产品类 A1
class ConcreteProductA1 implements ProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA1");
    }
}

// 具体产品类 A2
class ConcreteProductA2 implements ProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA2");
    }
}

// 抽象产品类 B
interface ProductB {
    void work();
}

// 具体产品类 B1
class ConcreteProductB1 implements ProductB {
    @Override
    public void work() {
        System.out.println("ConcreteProductB1 is working");
    }
}

// 具体产品类 B2
class ConcreteProductB2 implements ProductB {
    @Override
    public void work() {
        System.out.println("ConcreteProductB2 is working");
    }
}

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

// 具体工厂类 1,负责创建产品 A1 和产品 B1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂类 2,负责创建产品 A2 和产品 B2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 客户端代码
public class AbstractFactoryClient {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        productA1.use();
        ProductB productB1 = factory1.createProductB();
        productB1.work();

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        productA2.use();
        ProductB productB2 = factory2.createProductB();
        productB2.work();
    }
}

在上述代码中,为了便于理解,可以将抽象产品类a看成手机,抽象产品类b看成平板,而工厂1可以看作小米,工厂2看作apple

客户端的意思就是实现抽象工厂类类来创建具体工厂1小米,然后调用具体工厂的createProductA用来造小米手机,createProductB用来造小米平板,下面同理

总结:

● 简单工厂模式:实现简单,但不符合开闭原则,新增产品时需要修改工厂类代码。
● 工厂方法模式:符合开闭原则,新增产品时只需新增具体产品类和具体工厂类,无需修改现有代码。
● 抽象工厂模式:适用于创建一系列相关或相互依赖的对象,提供了更高层次的抽象和封装。

posted @ 2025-03-03 09:49  Zephyr07  阅读(72)  评论(0)    收藏  举报