几种常见的设计模式
设计模式是软件开发中解决常见问题的可重用方案。
以下是几种常见的设计模式,将使用 Go 语言和 C++ 语言分别简单实现,并说明它们解决的问题。
一、单例模式
解决的问题:
确保一个类只有一个实例,并提供全局访问点。适用于需要唯一控制资源(如配置管理器、日志记录器)的场景。
代码实现(go版本):
package main
import (
"fmt"
"sync"
)
type Singleton struct {
data string
}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{data: "I am the only instance"}
})
return instance
}
func main() {
s1 := GetInstance()
s2 := GetInstance()
fmt.Println(s1.data)
fmt.Println(s2 == s1) // true,说明是同一个实例
}
代码实现(c++版本):
#include <iostream>
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
std::string data;
// 私有构造函数,防止外部创建
Singleton() : data("I am the only instance") {}
public:
static Singleton* GetInstance() {
std::lock_guard<std::mutex> lock(mtx); // 线程安全
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
std::string GetData() const { return data; }
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
int main() {
Singleton* s1 = Singleton::GetInstance();
Singleton* s2 = Singleton::GetInstance();
std::cout << s1->GetData() << std::endl;
std::cout << (s1 == s2) << std::endl; // 输出 1,表示是同一实例
return 0;
}
二、工厂模式
解决的问题:
当需要创建的对象类型在运行时才能确定时,工厂模式隐藏对象的创建细节,提供统一的创建接口。适用于解耦对象创建与使用。
代码实现(go版本):
package main
import "fmt"
type Product interface {
Use() string
}
type ConcreteProductA struct{}
func (p *ConcreteProductA) Use() string { return "Product A" }
type ConcreteProductB struct{}
func (p *ConcreteProductB) Use() string { return "Product B" }
func CreateProduct(productType string) Product {
switch productType {
case "A":
return &ConcreteProductA{}
case "B":
return &ConcreteProductB{}
default:
return nil
}
}
func main() {
p1 := CreateProduct("A")
p2 := CreateProduct("B")
fmt.Println(p1.Use()) // Product A
fmt.Println(p2.Use()) // Product B
}
代码实现(c++版本):
#include <iostream>
#include <string>
class Product {
public:
virtual std::string Use() const = 0;
virtual ~Product() {}
};
class ConcreteProductA : public Product {
public:
std::string Use() const override { return "Product A"; }
};
class ConcreteProductB : public Product {
public:
std::string Use() const override { return "Product B"; }
};
class Factory {
public:
static Product* CreateProduct(const std::string& type) {
if (type == "A") return new ConcreteProductA();
if (type == "B") return new ConcreteProductB();
return nullptr;
}
};
int main() {
Product* p1 = Factory::CreateProduct("A");
Product* p2 = Factory::CreateProduct("B");
std::cout << p1->Use() << std::endl; // Product A
std::cout << p2->Use() << std::endl; // Product B
delete p1;
delete p2;
return 0;
}
通过 CreateProduct 函数根据参数动态创建对象,客户端无需关心具体实现类。
三、观察者模式
解决的问题:
定义对象间的一对多依赖关系,当一个对象状态变化时,所有依赖它的对象都能自动收到通知。适用于事件驱动系统。
代码实现(go版本):
package main
import "fmt"
type Subject struct {
observers []Observer
data string
}
type Observer interface {
Update(data string)
}
type ConcreteObserver struct {
name string
}
func (o *ConcreteObserver) Update(data string) {
fmt.Printf("%s received update: %s\n", o.name, data)
}
func (s *Subject) Attach(observer Observer) {
s.observers = append(s.observers, observer)
}
func (s *Subject) Notify() {
for _, observer := range s.observers {
observer.Update(s.data)
}
}
func (s *Subject) SetData(data string) {
s.data = data
s.Notify()
}
func main() {
subject := &Subject{}
observer1 := &ConcreteObserver{name: "Observer1"}
observer2 := &ConcreteObserver{name: "Observer2"}
subject.Attach(observer1)
subject.Attach(observer2)
subject.SetData("State changed!")
}
代码实现(c++版本):
#include <iostream>
#include <vector>
#include <string>
class Observer {
public:
virtual void Update(const std::string& data) = 0;
virtual ~Observer() {}
};
class Subject {
private:
std::vector<Observer*> observers;
std::string data;
public:
void Attach(Observer* observer) {
observers.push_back(observer);
}
void SetData(const std::string& newData) {
data = newData;
Notify();
}
void Notify() {
for (Observer* observer : observers) {
observer->Update(data);
}
}
};
class ConcreteObserver : public Observer {
private:
std::string name;
public:
ConcreteObserver(const std::string& n) : name(n) {}
void Update(const std::string& data) override {
std::cout << name << " received update: " << data << std::endl;
}
};
int main() {
Subject subject;
ConcreteObserver observer1("Observer1");
ConcreteObserver observer2("Observer2");
subject.Attach(&observer1);
subject.Attach(&observer2);
subject.SetData("State changed!");
return 0;
}
当 Subject 的状态改变时,调用 Notify 通知所有观察者,解决状态变化与依赖对象同步的问题。
四、策略模式
解决的问题:
将一组算法封装起来,使它们可以互换使用,客户端可以动态选择算法。适用于需要在运行时切换行为的场景。
代码实现(go版本):
package main
import "fmt"
type Strategy interface {
Execute(a, b int) int
}
type AddStrategy struct{}
func (s *AddStrategy) Execute(a, b int) int { return a + b }
type MultiplyStrategy struct{}
func (s *MultiplyStrategy) Execute(a, b int) int { return a * b }
type Context struct {
strategy Strategy
}
func (c *Context) SetStrategy(strategy Strategy) {
c.strategy = strategy
}
func (c *Context) ExecuteStrategy(a, b int) int {
return c.strategy.Execute(a, b)
}
func main() {
context := &Context{}
context.SetStrategy(&AddStrategy{})
fmt.Println(context.ExecuteStrategy(2, 3)) // 5
context.SetStrategy(&MultiplyStrategy{})
fmt.Println(context.ExecuteStrategy(2, 3)) // 6
}
代码实现(c++版本):
#include <iostream>
class Strategy {
public:
virtual int Execute(int a, int b) const = 0;
virtual ~Strategy() {}
};
class AddStrategy : public Strategy {
public:
int Execute(int a, int b) const override { return a + b; }
};
class MultiplyStrategy : public Strategy {
public:
int Execute(int a, int b) const override { return a * b; }
};
class Context {
private:
Strategy* strategy;
public:
Context() : strategy(nullptr) {}
void SetStrategy(Strategy* s) { strategy = s; }
int ExecuteStrategy(int a, int b) const {
if (strategy) return strategy->Execute(a, b);
return 0;
}
~Context() { delete strategy; } // 注意内存管理
};
int main() {
Context context;
context.SetStrategy(new AddStrategy());
std::cout << context.ExecuteStrategy(2, 3) << std::endl; // 5
context.SetStrategy(new MultiplyStrategy());
std::cout << context.ExecuteStrategy(2, 3) << std::endl; // 6
return 0;
}
通过 Context 动态切换策略(如加法或乘法),解决算法硬编码导致的扩展性问题。

浙公网安备 33010602011771号