经典设计模式:单例模式、工厂模式

1. 单例模式

1.1 懒汉式:在真正需要使用对象时才去创建该单例类对象

懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化**(判空),**若已实例化直接返回该类对象。否则则先执行实例化操作。

java 复制代码
public class Singleton {
    
    private static Singleton singleton;
    
    private Singleton(){}
    
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
    
}

懒汉式如何保证只创建一个对象

最容易想到的解决方法就是在方法上加锁,或者是对类对象加锁,

这样就规避了两个线程同时创建Singleton对象的风险,但是引来另外一个问题:每次去获取对象都需要先获取锁,并发性能非常地差,极端情况下,可能会出现卡顿现象。

接下来要做的就是优化性能,目标是:如果没有实例化对象则加锁创建,如果已经实例化了,则不需要加锁,直接获取实例

所以直接在方法上加锁的方式就被废掉了,因为这种方式无论如何都需要先获取锁

java 复制代码
public static Singleton getInstance() {
    if (singleton == null) {  // 线程A和线程B同时看到singleton = null,如果不为null,则直接返回singleton
        synchronized(Singleton.class) { // 线程A或线程B获得该锁进行初始化
            if (singleton == null) { // 其中一个线程进入该分支,另外一个线程则不会进入该分支
                singleton = new Singleton();
            }
        }
    }
    return singleton;
}

因为需要两次判空,且对类对象加锁,该懒汉式写法也被称为:Double Check(双重校验) + Lock(加锁)

1.2 饿汉式:在类加载时已经创建好该单例对象,等待被程序使用

饿汉式在类加载 时已经创建好该对象,在程序调用时直接返回 该单例对象即可,即我们在编码时就已经指明了要马上创建这个对象,不需要等到被调用时再去创建

java 复制代码
public class Singleton{
    
    private static final Singleton singleton = new Singleton();
    
    private Singleton(){}
    
    public static Singleton getInstance() {
        return singleton;
    }
}
typescript 复制代码
// 饿汉式单例
class EagerSingleton {
    private static readonly singleton: EagerSingleton = new EagerSingleton();
    
    private constructor() {}
    
    public static getInstance(): EagerSingleton {
        return EagerSingleton.singleton;
    }
}

// 懒汉式单例
class LazySingleton {
    private static singleton: LazySingleton;
    
    private constructor() {}
    
    public static getInstance(): LazySingleton {
        if (!LazySingleton.singleton) {
            LazySingleton.singleton = new LazySingleton();
        }
        return LazySingleton.singleton;
    }
}

// 验证饿汉式单例
const eager1 = EagerSingleton.getInstance();
const eager2 = EagerSingleton.getInstance();
console.log("饿汉式单例是否为同一实例:", eager1 === eager2); // 输出 true

// 验证懒汉式单例
const lazy1 = LazySingleton.getInstance();
const lazy2 = LazySingleton.getInstance();
console.log("懒汉式单例是否为同一实例:", lazy1 === lazy2); // 输出 true

2. 工厂模式

什么是工厂模式:

​ 工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

这三种模式从上到下逐步抽象,并且更具一般性。《设计模式》一书中将工厂模式分为两类:工厂方法模式与抽象工厂模式。将简单工厂模式看为工厂方法模式的一种特例,两者归为一类。

java 复制代码
public class BMW320 {
        public BMW320(){
                System.out.println("制造-->BMW320");
        }
}
 
public class BMW523 {
        public BMW523(){
                System.out.println("制造-->BMW523");
        }
}
 
public class Customer {
        public static void main(String[] args) {
                BMW320 bmw320 = new BMW320();
                BMW523 bmw523 = new BMW523();
        }
}

2.1 简单工厂模式

简单工厂模式的核心是定义一个创建对象的接口,将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。

代码实现

产品类:

java 复制代码
abstract class BMW {
        public BMW(){}
}
 
public class BMW320 extends BMW {
        public BMW320() {
                System.out.println("制造-->BMW320");
        }
}
public class BMW523 extends BMW{
        public BMW523(){
                System.out.println("制造-->BMW523");
        }
}

工厂类:

java 复制代码
public class Factory {
        public BMW createBMW(int type) {
                switch (type) {
                
                case 320:
                        return new BMW320();
 
                case 523:
                        return new BMW523();
 
                default:
                        break;
                }
                return null;
        }
}

用户类:

java 复制代码
public class Customer {
        public static void main(String[] args) {
                Factory factory = new Factory();
                BMW bmw320 = factory.createBMW(320);
                BMW bmw523 = factory.createBMW(523);
        }
}

优缺点

简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需知道具体产品类所对应的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

但缺点在于不符合"开闭原则",每次添加新产品就需要修改工厂类。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

为了解决简单工厂模式的问题,出现了工厂方法模式。

2.2 工厂方法模式

优缺点

工厂方法模式将工厂抽象化 ,并定义一个创建对象的接口 。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合"开闭原则"了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。

但缺点在于,每增加一个产品都需要增加一个具体产品类和实现工厂类,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

代码实现

产品类:

同简单工厂模式产品类

工厂类:

java 复制代码
interface FactoryBMW {
        BMW createBMW();
}
 
public class FactoryBMW320 implements FactoryBMW{
 
        @Override
        public BMW320 createBMW() {
                return new BMW320();
        }
 
}
public class FactoryBMW523 implements FactoryBMW {
        @Override
        public BMW523 createBMW() {
                return new BMW523();
        }
}

客户类:

java 复制代码
public class Customer {
        public static void main(String[] args) {
                FactoryBMW320 factoryBMW320 = new FactoryBMW320();
                BMW320 bmw320 = factoryBMW320.createBMW();
 
                FactoryBMW523 factoryBMW523 = new FactoryBMW523();
                BMW523 bmw523 = factoryBMW523.createBMW();
        }
}

2.3 抽象工厂模式

优缺点

抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

代码实现

产品类:

java 复制代码
//发动机以及型号  
public interface Engine {}  
 
public class EngineA implements Engine{  
    public EngineA(){  
        System.out.println("制造-->EngineA");  
    }  
}  
public class EngineB implements Engine{  
    public EngineB(){  
        System.out.println("制造-->EngineB");  
    }  
}  
 
 
//空调以及型号  
public interface Aircondition {} 
 
public class AirconditionA implements Aircondition{  
    public AirconditionA(){  
        System.out.println("制造-->AirconditionA");  
    }  
}  
public class AirconditionB implements Aircondition{  
    public AirconditionB(){  
        System.out.println("制造-->AirconditionB");  
    }  
} 

工厂类:

java 复制代码
//创建工厂的接口  
public interface AbstractFactory {  
    //制造发动机
    public Engine createEngine();
    //制造空调 
    public Aircondition createAircondition(); 
}  
 
//为宝马320系列生产配件  
public class FactoryBMW320 implements AbstractFactory{     
    @Override  
    public Engine createEngine() {    
        return new EngineA();  
    }  
    @Override  
    public Aircondition createAircondition() {  
        return new AirconditionA();  
    }  
}  
//宝马523系列
public class FactoryBMW523 implements AbstractFactory {  
     @Override  
    public Engine createEngine() {    
        return new EngineB();  
    }  
    @Override  
    public Aircondition createAircondition() {  
        return new AirconditionB();  
    }  
} 

客户类:

java 复制代码
//创建工厂的接口  
public interface AbstractFactory {  
    //制造发动机
    public Engine createEngine();
    //制造空调 
    public Aircondition createAircondition(); 
}  
 
//为宝马320系列生产配件  
public class FactoryBMW320 implements AbstractFactory{     
    @Override  
    public Engine createEngine() {    
        return new EngineA();  
    }  
    @Override  
    public Aircondition createAircondition() {  
        return new AirconditionA();  
    }  
}  
//宝马523系列
public class FactoryBMW523 implements AbstractFactory {  
     @Override  
    public Engine createEngine() {    
        return new EngineB();  
    }  
    @Override  
    public Aircondition createAircondition() {  
        return new AirconditionB();  
    }  
} 

参考:

我给面试官讲解了单例模式后,他对我竖起了大拇指!

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

相关推荐
福大大架构师每日一题4 小时前
go 1.25.1发布:重点修复net/http跨域保护安全漏洞(CVE-2025-47910)
开发语言·http·golang
Chan164 小时前
消息推送的三种常见方式:轮询、SSE、WebSocket
java·网络·websocket·网络协议·http·sse
Dear.爬虫4 小时前
Golang中逃逸现象, 变量“何时栈?何时堆?”
开发语言·后端·golang
小薛博客5 小时前
22、Jenkins容器化部署Java应用
java·运维·jenkins
编码浪子5 小时前
趣味学RUST基础篇(构建一个命令行程序2重构)
开发语言·重构·rust
西贝爱学习5 小时前
如何在 IntelliJ IDEA 中进行全局替换某个字段(或文本)
java·ide·intellij-idea
南部余额5 小时前
Spring 基于注解的自动化事务
java·spring·自动化
alf_cee5 小时前
通过Idea 阿里插件快速部署java jar包
java·ide·intellij-idea
坚持每天敲代码5 小时前
【教程】IDEA中导入springboot-maven工程
java·maven·intellij-idea