工厂模式和单例模式的学习
单例模式
概念:
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用来造小米平板,下面同理
总结:
● 简单工厂模式:实现简单,但不符合开闭原则,新增产品时需要修改工厂类代码。
● 工厂方法模式:符合开闭原则,新增产品时只需新增具体产品类和具体工厂类,无需修改现有代码。
● 抽象工厂模式:适用于创建一系列相关或相互依赖的对象,提供了更高层次的抽象和封装。

浙公网安备 33010602011771号