单例模式有哪几种实现?如何保证线程安全?
单例模式常见有:**饿汉式、懒汉式(线程安全版需要加双重检查锁定)、静态内部类、枚举单例(Java特有)**等几个实现方式。
- 饿汉式:实例在类加载时创建,线程安全,但如果实例初始化较重或没有被使用会浪费资源。
- 懒汉式:实例在首次访问时创建,节约资源,但需要确保线程安全。
- 双重检查锁定:在懒汉式的基础上优化,直接加锁效率太低,双重检查锁只在第一次检查实例为空时加锁,提高性能。
- 静态内部类:利用类加载机制实现懒加载和线程安全,推荐使用。
- 枚举单例(Java特有):通过枚举实现单例,简单且防止反射和序列化攻击。
如何保证线程安全? - Java:推荐静态内部类或双重检查锁定,配合volatile。
- C++:推荐使用std::call_once或mutex实现线程安全。
- Python:使用__new__方法或装饰器实现,配合线程锁确保安全。
- Go:使用sync.Once。
什么是策略模式?一般用在什么场景?
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使他们可以互相替换,让算法独立于使用它的客户端(调用方)而变化。
很多情况下,我们代码里有大量的if else、switch等,可以通过使用策略模式,避免大量条件语句的使用,实现算法的分离和独立变化。
它的主要目的是为了解耦多个策略,并方便调用方在针对不同场景灵活切换不同的策略。
策略模式的特点:
- 算法封装:将算法的实现与使用算法的代码分离,通过封装提高代码的灵活性和可扩展性。
- 动态替换:可以在运行时选择和替换算法。
- 遵循开闭原则:新增策略无需修改现有代码。
一般使用在什么场景?
- 多种算法可互换:需要动态选择算法,例如排序算法的选择。
- 避免条件语句:通过策略模式替代代码中大量的if-else或switch语句。
- 与上下文独立:客户端不需要知道具体的算法实现细节,只需要依赖抽象策略。
典型场景:
- 支付系统:支持多种支付方式。
- 数据压缩:提供不同的压缩算法。
- 日志策略:根据日志级别动态选择记录策略。
什么是模板方法模式?一般用在什么场景?
模板方法模式是一种行为型设计模式,它在一个抽象类中定义了一个算法(业务逻辑)的骨架,具体步骤的实现由子类提供,它通过将算法的不变部分放在抽象类中,可变部分放在子类中,达到代码复用和扩展的目的
- 复用:所有子类可以直接复用父类提供的模板方法,即上面提到的不变的部分。
- 扩展:子类可以通过模板定义的一些扩展点就行不同的定制化实现。
模板方法模式的特点:
- 算法骨架:在基类中定义一个算法的固定执行步骤(模板方法),具体实现步骤交给子类完成。
- 复用代码:子类复用基类中定义的通用逻辑,仅需实现特定步骤。
- 遵循开闭原则:基类的骨架逻辑对扩展开放,对修改关闭。
一般使用在什么场景?
- 定义算法骨架:有一个固定的流程,但某些步骤需要根据具体情况自定义。
- 复用公共逻辑:多个子类共享相同的算法结构,仅需重写特定步骤。
- 控制执行顺序:需要对子类执行方法的顺序进行控制时。
典型场景:
- 数据处理流程:如读取数据、处理数据、输出结果。
- Web请求处理:如解析请求、处理逻辑、返回相应。