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

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

一、单例模式

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

1. Java 的单例模式实现

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

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

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

    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 保证),可防止反射和序列化破坏,是最安全的实现。

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

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

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

    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函数前执行,且是单线程的(天然线程安全),适合无需延迟初始化的场景。

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

    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 是强类型面向对象语言,支持类继承接口显式实现,工厂模式通常通过 “工厂类 + 接口” 实现,结构更严谨。

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

    // 产品接口
    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");
    
  • 工厂方法:每个产品对应一个工厂类,工厂类实现统一的工厂接口(遵循开闭原则,扩展方便)。

    // 工厂接口
    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();
    
  • 抽象工厂:创建一系列相关产品,工厂接口定义多个产品创建方法,具体工厂实现所有方法。

    // 抽象产品族
    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关键字),且函数是一等公民,工厂模式通常通过函数(而非工厂类) 实现,更简洁灵活。

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

    // 产品接口
    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()
    
  • 工厂方法:通过 “工厂函数类型” 或 “结构体方法” 实现,无需定义工厂接口(依赖隐式匹配)。

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

    // 产品族接口
    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,编译期严格检查隐式实现(结构匹配接口即可),更灵活
扩展性依赖类继承,扩展需新增工厂类依赖函数或结构体组合,扩展更轻量
产品族支持(抽象工厂)通过接口定义多个创建方法,结构严谨通过函数组或结构体字段组合,更简洁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值