您的位置:

Golang单例模式

一、Golang单例模式实现

单例模式是一种常见的设计模式,它保证在整个程序中只会有一个实例对象被创建和使用。在某些情况下,只需要一个对象,例如在配置信息中心。在Golang中,实现单例模式需要考虑Golang的并发特性。

下面是一个常见的经典实现,使用懒惰初始化的方法来确保只会实例化一次实例对象。

type Singleton struct {
}

var instance *Singleton

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

var once sync.Once

在这个实现中,Golang标准库提供了一个sync.Once类型来确保初始化动作只执行一次。在GetInstance()方法中,我们首先判断实例对象是否已经被创建,如果没有,那么就使用once.Do()方法创建一个实例。

二、Golang工厂模式

Golang工厂模式是一种创建型的设计模式,它定义了一个对象创建的接口,但是让子类决定实例化哪个类。这种方式可以避免暴露对象创建的具体实现逻辑。

下面是一个简单的Golang工厂模式实现,它使用GetAnimal()方法来根据输入的动物名创建对应的动物对象。

type Animal interface {
    Speak() string
}

type Dog struct{}

func (d Dog) Speak() string {
    return "Woof!"
}

type Cat struct{}

func (c Cat) Speak() string {
    return "Meow!"
}

func GetAnimal(animalType string) Animal {
    switch animalType {
    case "dog":
        return Dog{}
    case "cat":
        return Cat{}
    default:
        return nil
    }
}

在这个实现中,我们定义了一个Animal接口和两个实现类:Dog和Cat。GetAnimal()方法根据输入的字符串来返回对应的动物对象。

三、Go单例模式

Go单例模式是一种用于解决资源竞争问题的实现方式。如果多个协程同时访问某个变量,会出现资源访问冲突的问题。Go单例模式通过使用channel来限制只有一个协程在任何时刻访问共享资源。

下面是一个简单的Go单例模式实现,其中使用了无缓冲的channel来同步协程之间的访问。

type Singleton struct{}

var once sync.Once
var instance *Singleton
var ch = make(chan int, 1)

func GetInstance() *Singleton {
    if instance == nil {
        ch <- 1
        defer func() { <-ch }()
        once.Do(func() {
            instance = &Singleton{}
        })
    }
    return instance
}

在这个实现中,我们定义了一个无缓冲的channel来控制多个协程之间的访问。在GetInstance()方法中,我们首先将ch的一个元素压入队列中,然后在函数退出时将其出队。这样,可以确保在任何时刻只有一个协程能够访问代码块中的内容。

四、Golang设计模式

设计模式是一种解决软件工程中常见问题的经验总结,它帮助开发者对程序进行架构和设计,提高软件的可维护性、可扩展性和可重用性。Golang支持大多数常见的设计模式。

下面是一些常见的Golang设计模式:

1. 观察者模式

观察者模式定义了对象之间的一种依赖关系,当被观察对象状态发生变化时,所有依赖于它的观察者都将得到通知。在Golang中,可以使用channel来实现观察者模式。

type Observer interface {
    Update(int)
}

type Subject struct {
    observers []Observer
}

func (s *Subject) Attach(o Observer) {
    s.observers = append(s.observers, o)
}

func (s *Subject) Notify(val int) {
    for _, observer := range s.observers {
        observer.Update(val)
    }
}

type ConcreteObserver struct{}

func (c *ConcreteObserver) Update(val int) {
    fmt.Printf("Received update with value %v\n", val)
}

func runObserverPattern() {
    subj := &Subject{observers: []Observer{&ConcreteObserver{}}}
    subj.Notify(10)
}

2. 策略模式

策略模式定义了一系列算法,将每个算法封装为一个单独的类,并让它们可以互换。这种设计模式可以使算法独立于使用它的客户端而变化。

type Strategy interface {
    Execute()
}

type ConcreteStrategy1 struct{}

func (s1 *ConcreteStrategy1) Execute() {
    fmt.Println("Executing Concrete Strategy 1...")
}

type ConcreteStrategy2 struct{}

func (s2 *ConcreteStrategy2) Execute() {
    fmt.Println("Executing Concrete Strategy 2...")
}

type Context struct {
    strategy Strategy
}

func (c *Context) SetStrategy(strategy Strategy) {
    c.strategy = strategy
}

func (c *Context) Execute() {
    c.strategy.Execute()
}

func runStrategyPattern() {
    c := &Context{}
    c.SetStrategy(&ConcreteStrategy1{})
    c.Execute()

    c.SetStrategy(&ConcreteStrategy2{})
    c.Execute()
}

3. 访问者模式

访问者模式是一种行为型模式,它将某些算法封装到类中。在Golang中,访问者模式通常使用函数代替类来实现。

type Element interface {
    Accept(Visitor)
}

type ConcreteElement1 struct{}

func (e1 *ConcreteElement1) Accept(v Visitor) {
    v.VisitConcreteElement1(e1)
}

type ConcreteElement2 struct{}

func (e2 *ConcreteElement2) Accept(v Visitor) {
    v.VisitConcreteElement2(e2)
}

type Visitor interface {
    VisitConcreteElement1(*ConcreteElement1)
    VisitConcreteElement2(*ConcreteElement2)
}

type ConcreteVisitor struct{}

func (c *ConcreteVisitor) VisitConcreteElement1(e1 *ConcreteElement1) {
    fmt.Println("Visiting Concrete Element 1 by Concrete Visitor...")
}

func (c *ConcreteVisitor) VisitConcreteElement2(e2 *ConcreteElement2) {
    fmt.Println("Visiting Concrete Element 2 by Concrete Visitor...")
}

func runVisitorPattern() {
    elements := []Element{&ConcreteElement1{}, &ConcreteElement2{}}
    v := &ConcreteVisitor{}
    for _, el := range elements {
        el.Accept(v)
    }
}

4. ACM模式

ACM(Active Class Middleware)模式是一种以类为中心的分布式体系结构模式。在ACM模式中,运行时环境中有许多对象扮演不同的角色,这些对象在运行过程中相互作用,以实现分布式系统的功能。

在Golang中,可以通过使用GRPC实现ACM模式。

下面是一个简单的GRPC示例:

// server
type GreeterServer struct{}

func (s *GreeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 50051))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &GreeterServer{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

// client
func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)
    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "World"})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

五、总结

Golang单例模式是一种常见的设计模式,它保证在整个程序中只会有一个实例对象被创建和使用。在Golang中,实现单例模式需要考虑Golang的并发特性。此外,Golang还支持许多其他常见的设计模式,例如工厂模式、观察者模式、策略模式、访问者模式和ACM模式。