文章目录
单例模式
- 什么是单例? 系统运行期间有且仅有一个实例。
- 为什么要有单例?系统中的一些对象只需要初始化一次即可,例如:KTV中的播放器或者初始化系统参数
- 单例模式的要求:
- 一个类只有一个实例 只提供私有的构造器。
private SingletonClass(){ }
- 必须自己创建这个实例 定义该类的静态私有对象。
private static SingletonClass single;
- 必须自己向系统提供这个实例。 创建一个公共的静态方法,返回这个实例。
public static SingletonClass getSingleton(){ if(single==null){ initSingleton(); } return single; }
饿汉模式
不管你用不用我都给你创建这个实例。(官方语言:在类加载的时候创建这个实例)。 天然线程安全的,每个类中获取这个对象的耗时基本一样
下面是饿汉模式,使用静态内部类实现延迟加载。
public class SingleTon {
private SingleTon() {
}
private static SingleTon singleTon;
// 静态内部类
public static class SingletonHelper{
private static final SingleTon INSTANCE = new SingleTon();
}
public static SingleTon getSingleTon() {
singleTon = SingletonHelper.INSTANCE;
return singleTon;
}
}
懒汉模式
在你调用的时候才创建这个实例。不是线程安全,第一次获取此对象会耗时较多
- 线程安全问题
- double check 加锁优化
- 编译器(JIT),CPU有可能对指令执行重新排序,导致使用到尚未初始化的实例(nullpointException),可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排。
/**
* 手写一个单例模式
*/
public class SingletonClass {
// 1.私有化构造方法,收回创建实例的权限
private SingletonClass(){
}
// 2.自己声明这个实例对象
private volatile static SingletonClass singletonClass;
// 3.向系统提供一个公共的方法,获取这个实例
public static SingletonClass getInstance(){
if(singletonClass==null){ // 为空才加同步锁,锁的范围越小越好
synchronized (SingletonClass.class){
if(singletonClass==null){ // 判断是否为空,防止实例化两次
singletonClass = new SingletonClass();
// 字节码 其中2和3可能存在重排的问题,如果3在前,在多线程的情况下会出现空指针
// 1.分配空间
// 2.初始化
// 3.引用赋值
}
}
}
return singletonClass;
}
}
对比
- 线程安全:饿汉式天生就是线程安全的,懒汉式本身是非线程安全的。
- 资源加载和性能:饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
工厂模式
- 什么是工厂? 将对象的创建过程封装在一个工厂类中,通过调用工厂类的方法来获取对象实例,而不需要直接使用new关键字来创建对象
- 为什么要有工厂模式? 工厂模式能够提供更好的代码组织结构、更好的封装性、更好的可扩展性和更好的解耦性,从而提高了代码的质量和可维护性
- 工厂模式的要求
- 抽象产品:定义产品的共同接口或抽象类,描述产品的特征和行为。
- 具体产品:实现抽象产品接口或继承抽象产品类,是工厂创建的目标对象。
// 抽象产品接口
public interface Product {
void operation1();
void operation2();
}
// 具体类A
public class ConcreteProductA implements Product {
@Override
public void operation1() {
// 具体类A的操作1
}
@Override
public void operation2() {
// 具体类A的操作2
}
}
// 具体类B
public class ConcreteProductB implements Product {
@Override
public void operation1() {
// 具体类B的操作1
}
@Override
public void operation2() {
// 具体类B的操作2
}
}
- 抽象工厂:定义工厂的共同接口或抽象类,描述创建产品的方法。
- 具体工厂:实现抽象工厂接口或继承抽象工厂类,负责实际创建产品的类。
- 客户端:使用工厂创建产品的代码,通过工厂接口来创建所需的产品对象。
# 定义抽象工厂接口
class AbstractFactory:
def create_product_a(self):
pass
def create_product_b(self):
pass
# 实现具体的工厂类
class ConcreteFactory1(AbstractFactory):
def create_product_a(self):
return ProductA1()
def create_product_b(self):
return ProductB1()
class ConcreteFactory2(AbstractFactory):
def create_product_a(self):
return ProductA2()
def create_product_b(self):
return ProductB2()
# 定义产品接口
class AbstractProductA:
def do_something(self):
pass
class AbstractProductB:
def do_something(self):
pass
# 实现具体类
class ProductA1(AbstractProductA):
def do_something(self):
print("Product A1")
class ProductA2(AbstractProductA):
def do_something(self):
print("Product A2")
class ProductB1(AbstractProductB):
def do_something(self):
print("Product B1")
class ProductB2(AbstractProductB):
def do_something(self):
print("Product B2")
# 客户端代码
def client_code(factory):
product_a = factory.create_product_a()
product_b = factory.create_product_b()
product_a.do_something()
product_b.do_something()
# 使用具体工厂1
factory1 = ConcreteFactory1()
client_code(factory1)
# 使用具体工厂2
factory2 = ConcreteFactory2()
client_code(factory2)
简单工厂模式(Simple Factory Pattern)
简单工厂模式又称为静态工厂模式,它由一个工厂类来负责创建所有的产品对象。客户端只需要通过工厂类来创建产品对象,而不需要直接实例化具体产品类。简单工厂模式的核心是一个工厂类,它包含一个创建产品的方法,根据客户端传入的参数来决定创建哪种产品。
# 定义产品接口
class Product:
def show(self):
pass
# 定义具体类A,实现接口
class ConcreteProductA(Product):
def show(self):
print("Concrete Product A")
# 定义具体类B,实现接口
class ConcreteProductB(Product):
def show(self):
print("Concrete Product B")
# 定义静态工厂类
class StaticFactory:
@staticmethod
def create_product(product_type):
if product_type == "A":
return ConcreteProductA()
elif product_type == "B":
return ConcreteProductB()
else:
raise ValueError("Invalid product type")
# 客户端代码
if __name__ == "__main__":
product_a = StaticFactory.create_product("A") # 使用静态工厂类创建具体A
product_a.show() # 调用具体A的方法,输出 "Concrete Product A"
product_b = StaticFactory.create_product("B") # 使用静态工厂类创建具体B
product_b.show() # 调用具体B的方法,输出 "Concrete Product B"
工厂方法模式(Factory Method Pattern)
工厂方法模式将具体产品的创建过程延迟到子类中进行,每个具体产品都对应一个具体工厂类。客户端通过调用工厂方法来创建产品对象,工厂方法由子类实现,以创建对应的具体产品对象。
// 抽象类
public abstract class Product {
public abstract void use();
}
// 具体类A
public class ConcreteProductA extends Product {
@Override
public void use() {
System.out.println("使用具体类A");
}
}
// 具体类B
public class ConcreteProductB extends Product {
@Override
public void use() {
System.out.println("使用具体类B");
}
}
// 抽象工厂类
public abstract class Factory {
public abstract Product createProduct();
}
// 工厂类A
public class ConcreteFactoryA extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 工厂类B
public class ConcreteFactoryB extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端代码
public class Client {
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();
}
}
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定其具体类。抽象工厂模式包含一个抽象工厂接口,定义了用于创建产品对象的方法,具体工厂类实现了抽象工厂接口,并负责创建一系列相关产品。每个具体工厂类都对应于一个产品族,可以创建该产品族的多个产品。
// 定义抽象A
interface AbstractProductA {
void operationA();
}
// 定义具体A1
class ConcreteProductA1 implements AbstractProductA {
public void operationA() {
System.out.println("Product A1");
}
}
// 定义具体A2
class ConcreteProductA2 implements AbstractProductA {
public void operationA() {
System.out.println("Product A2");
}
}
// 定义抽象B
interface AbstractProductB {
void operationB();
}
// 定义具体B1
class ConcreteProductB1 implements AbstractProductB {
public void operationB() {
System.out.println("Product B1");
}
}
// 定义具体B2
class ConcreteProductB2 implements AbstractProductB {
public void operationB() {
System.out.println("Product B2");
}
}
// 定义抽象工厂
interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
// 定义具体工厂1
class ConcreteFactory1 implements AbstractFactory {
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
// 定义具体工厂2
class ConcreteFactory2 implements AbstractFactory {
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
// 调用方
public class Client {
public static void main(String[] args) {
// 创建工厂1
AbstractFactory factory1 = new ConcreteFactory1();
// 使用工厂1创建A和B
AbstractProductA productA1 = factory1.createProductA();
AbstractProductB productB1 = factory1.createProductB();
productA1.operationA();
productB1.operationB();
// 创建工厂2
AbstractFactory factory2 = new ConcreteFactory2();
// 使用工厂2创建A和B
AbstractProductA productA2 = factory2.createProductA();
AbstractProductB productB2 = factory2.createProductB();
productA2.operationA();
productB2.operationB();
}
}
对比
- 简单工厂模式适用于对象种类较少且不会频繁变化的情况,工厂方法模式适用于对象种类较多且可能会有新产品增加的情况,抽象工厂模式适用于创建一组相关或相互依赖的产品且可能会有新的产品组合增加的情况。根据具体的需求和场景,选择适合的工厂模式可以提高代码的灵活性和可维护性。
- 简单工厂模式是通过一个工厂类来创建所有的产品对象,根据不同的参数返回不同的具体产品对象。在多线程环境下,如果多个线程同时调用工厂的创建方法,可能会导致线程安全问题。解决这个问题的一种方式是在工厂类的创建方法上加锁,保证同一时间只有一个线程能够调用该方法。
- 工厂方法模式将产品的创建延迟到子类中,每个产品有一个对应的工厂类来创建。在多线程环境下,每个线程独立使用各自的工厂类创建产品对象,不存在线程安全问题。不同的线程可以并发调用不同的工厂类创建产品,互不干扰。
- 抽象工厂模式通过提供一个接口来创建一系列相关或依赖对象的家族,而不需要指定具体的类。在多线程环境下,如果多个线程同时调用不同的具体工厂类创建产品对象,也不存在线程安全问题。不同的线程可以并发调用不同的具体工厂类创建产品,互不干扰。