Golang 与Java 单例模式、工厂模式比较

为了便于理解Golang的设计模式,将其与Java的设计模式对比,可以为之前熟悉Java的同学提供一个便利的思路; Golang 和 Java 在实现单例模式、工厂模式时,因语言特性(如面向对象模型、并发机制、类型系统等)的差异,呈现出不同的设计思路和实现方式。以下从两种模式分别对比分析:

一、单例模式

单例模式的核心是确保一个类型只有唯一实例,并提供全局访问点。两者的实现差异主要源于语言的并发模型、对象创建方式和访问控制机制。

1. Java 的单例模式实现

Java 是纯面向对象语言,基于类和对象模型,单例通常通过私有构造函数 + 静态方法 实现,需重点解决线程安全反射 / 序列化破坏单例的问题。常见实现方式:

饿汉式:类加载时初始化实例,天然线程安全(JVM 类加载机制保证),但可能提前占用资源。

java 复制代码
public class Singleton {
    // 类加载时初始化
    private static final Singleton INSTANCE = new Singleton();
    // 私有构造函数,禁止外部创建
    private Singleton() {}
    // 全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
  • 懒汉式(双重检查锁定) :延迟初始化,通过synchronizedvolatile保证线程安全(避免指令重排序导致的空指针)。

    java 复制代码
    public class Singleton {
        // volatile防止指令重排序
        private static volatile Singleton INSTANCE;
        private Singleton() {}
        public static Singleton getInstance() {
            if (INSTANCE == null) { // 第一次检查(无锁,提高效率)
                synchronized (Singleton.class) {
                    if (INSTANCE == null) { // 第二次检查(加锁,确保唯一)
                        INSTANCE = new Singleton();
                    }
                }
            }
            return INSTANCE;
        }
    }
  • 枚举单例:利用枚举的天然单例特性(JVM 保证),可防止反射和序列化破坏,是最安全的实现。

    java 复制代码
    public enum Singleton {
        INSTANCE; // 唯一实例
        // 业务方法
        public void doSomething() {}
    }
2. Golang 的单例模式实现

Golang 无 "类" 概念,基于结构体(struct)包级变量 ,单例实现依赖语言的并发原语(如sync.Oncesync.Mutex访问控制(首字母大小写)。核心是保证并发安全的初始化。

  • sync.Once实现 :Golang 推荐方式,sync.Once确保初始化代码仅执行一次,天然线程安全(适用于 goroutine 并发场景)。

    Go 复制代码
    package singleton
    
    import "sync"
    
    // 结构体首字母小写,包外不可直接访问
    type singleton struct{}
    
    var (
        instance *singleton
        once     sync.Once // 保证初始化只执行一次
    )
    
    // 全局访问点(首字母大写,包外可调用)
    func GetInstance() *singleton {
        once.Do(func() { // 初始化逻辑仅执行一次
            instance = &singleton{}
        })
        return instance
    }
  • 包级变量实现 :Golang 包初始化在main函数前执行,且是单线程的(天然线程安全),适合无需延迟初始化的场景。

    Go 复制代码
    package singleton
    
    type Singleton struct{}
    
    // 包初始化时创建实例,包外通过变量直接访问
    var Instance = &Singleton{}
  • 互斥锁实现 :类似 Java 的双重检查,但 Golang 的sync.Mutex更轻量,适合需要手动控制初始化时机的场景。

    Go 复制代码
    package singleton
    
    import "sync"
    
    type singleton struct{}
    
    var (
        instance *singleton
        mu       sync.Mutex
        initialized bool
    )
    
    func GetInstance() *singleton {
        if !initialized { // 第一次检查(无锁)
            mu.Lock()
            defer mu.Unlock()
            if !initialized { // 第二次检查(加锁)
                instance = &singleton{}
                initialized = true
            }
        }
        return instance
    }
单例模式核心差异
维度 Java 特点 Golang 特点
实现基础 基于类和对象,依赖私有构造函数限制创建 基于结构体和包,依赖首字母小写限制访问
线程安全机制 依赖synchronizedvolatile或枚举特性 依赖sync.Once(推荐)、sync.Mutex或包初始化机制
延迟初始化 需手动实现(如双重检查) 天然支持(sync.Once+ 函数调用)
防破坏机制 需额外处理反射 / 序列化(枚举单例除外) 无需考虑(无反射破坏单例的常见场景)

二、工厂模式

工厂模式的核心是隐藏对象创建逻辑,通过 "工厂" 统一生成实例,分为简单工厂、工厂方法、抽象工厂。两者的差异源于类型系统(接口实现方式、继承支持)和函数特性。

1. Java 的工厂模式实现

Java 是强类型面向对象语言,支持类继承接口显式实现,工厂模式通常通过 "工厂类 + 接口" 实现,结构更严谨。

  • 简单工厂:一个工厂类通过静态方法根据参数创建不同子类实例(违反开闭原则,但简单直观)。

    java 复制代码
    // 产品接口
    public interface Product {
        void use();
    }
    // 具体产品
    public class ProductA implements Product {
        @Override public void use() { /* 实现 */ }
    }
    public class ProductB implements Product {
        @Override public void use() { /* 实现 */ }
    }
    // 简单工厂类
    public class SimpleFactory {
        public static Product createProduct(String type) {
            if ("A".equals(type)) return new ProductA();
            if ("B".equals(type)) return new ProductB();
            throw new IllegalArgumentException("无效类型");
        }
    }
    // 使用
    Product p = SimpleFactory.createProduct("A");
  • 工厂方法:每个产品对应一个工厂类,工厂类实现统一的工厂接口(遵循开闭原则,扩展方便)。

    java 复制代码
    // 工厂接口
    public interface Factory {
        Product create();
    }
    // 具体工厂
    public class FactoryA implements Factory {
        @Override public Product create() { return new ProductA(); }
    }
    public class FactoryB implements Factory {
        @Override public Product create() { return new ProductB(); }
    }
    // 使用
    Factory factory = new FactoryA();
    Product p = factory.create();
  • 抽象工厂:创建一系列相关产品,工厂接口定义多个产品创建方法,具体工厂实现所有方法。

    java 复制代码
    // 抽象产品族
    public interface ProductA {}
    public interface ProductB {}
    // 具体产品
    public class ConcreteProductA1 implements ProductA {}
    public class ConcreteProductB1 implements ProductB {}
    // 抽象工厂
    public interface AbstractFactory {
        ProductA createProductA();
        ProductB createProductB();
    }
    // 具体工厂(生产一套产品)
    public class Factory1 implements AbstractFactory {
        @Override public ProductA createProductA() { return new ConcreteProductA1(); }
        @Override public ProductB createProductB() { return new ConcreteProductB1(); }
    }
2. Golang 的工厂模式实现

Golang 无类继承,但支持接口隐式实现 (无需implements关键字),且函数是一等公民,工厂模式通常通过函数(而非工厂类) 实现,更简洁灵活。

  • 简单工厂:通过一个函数根据参数返回不同结构体实例(结构体隐式实现同一接口)。

    Go 复制代码
    // 产品接口
    type Product interface {
        Use()
    }
    // 具体产品
    type ProductA struct{}
    func (a *ProductA) Use() { /* 实现 */ }
    type ProductB struct{}
    func (b *ProductB) Use() { /* 实现 */ }
    // 简单工厂函数
    func NewProduct(t string) (Product, error) {
        switch t {
        case "A":
            return &ProductA{}, nil
        case "B":
            return &ProductB{}, nil
        default:
            return nil, fmt.Errorf("无效类型")
        }
    }
    // 使用
    p, _ := NewProduct("A")
    p.Use()
  • 工厂方法:通过 "工厂函数类型" 或 "结构体方法" 实现,无需定义工厂接口(依赖隐式匹配)。

    Go 复制代码
    // 工厂函数类型(返回Product的函数)
    type Factory func() Product
    // 具体工厂函数
    func NewProductA() Product { return &ProductA{} }
    func NewProductB() Product { return &ProductB{} }
    // 使用
    var factory Factory = NewProductA
    p := factory()
  • 抽象工厂:通过一组相关的工厂函数实现,返回不同接口的实例(模拟产品族)。

    Go 复制代码
    // 产品族接口
    type ProductA interface { DoA() }
    type ProductB interface { DoB() }
    // 具体产品
    type ConcreteA1 struct{}
    func (a *ConcreteA1) DoA() {}
    type ConcreteB1 struct{}
    func (b *ConcreteB1) DoB() {}
    // 抽象工厂(一组函数)
    type AbstractFactory struct {
        NewA func() ProductA
        NewB func() ProductB
    }
    // 具体工厂(初始化函数组)
    var Factory1 = AbstractFactory{
        NewA: func() ProductA { return &ConcreteA1{} },
        NewB: func() ProductB { return &ConcreteB1{} },
    }
    // 使用
    a := Factory1.NewA()
    b := Factory1.NewB()
工厂模式核心差异
维度 Java 特点 Golang 特点
实现载体 基于工厂类(实现工厂接口) 基于工厂函数(或函数组),无需工厂类
接口实现 显式声明implements,编译期严格检查 隐式实现(结构匹配接口即可),更灵活
扩展性 依赖类继承,扩展需新增工厂类 依赖函数或结构体组合,扩展更轻量
产品族支持(抽象工厂) 通过接口定义多个创建方法,结构严谨 通过函数组或结构体字段组合,更简洁
相关推荐
Funcy7 小时前
XxlJob源码分析01:环境准备
java
the beard7 小时前
Feign整合Sentinel实现服务降级与Feign拦截器实战指南
java·spring·sentinel
THMAIL8 小时前
攻克 Java 分布式难题:并发模型优化与分布式事务处理实战指南
java·开发语言·分布式
完美世界的一天8 小时前
Golang 面试题「中级」
开发语言·后端·面试·golang
小沈同学呀8 小时前
使用Java操作微软 Azure Blob Storage:上传和下载文件
java·microsoft·azure
CYRUS_STUDIO9 小时前
一步步带你移植 FART 到 Android 10,实现自动化脱壳
android·java·逆向
练习时长一年9 小时前
Spring代理的特点
java·前端·spring
CYRUS_STUDIO9 小时前
FART 主动调用组件深度解析:破解 ART 下函数抽取壳的终极武器
android·java·逆向
MisterZhang66610 小时前
Java使用apache.commons.math3的DBSCAN实现自动聚类
java·人工智能·机器学习·自然语言处理·nlp·聚类
逢生博客10 小时前
使用 SmartIDE 开发长安链 Go 语言智能合约
golang·web3·区块链·智能合约·长安链