Singleton:确保每一类只有一个实例,并且提供对这个实例的全局访问

  1. 通常用于需要共享的资源。例如数据库对象
  2. Singleton还是一种有效保护使变量免遭改写的技术

实现方法

  • 构造函数私有化
  • 用一个静态函数作为constructor,通过它创建一个新对象并存储在一个静态空间里

Python中的实现有一些魔法,其中一个就是Python中任何东西都是对象,包括类本身也是对象。type本质上不是类,而是一个元类。type(1)输出结果是<class 'int'>,表明它创建了一个类!

1
2
class Foo:
a = 1

实际上也可以这样写:

1
2
# type(name, bases, dict)
type(Foo, (object,), {"a":1})

使用元类的目的:控制类的产生过程和对象的产生过程。继承type就可以产生元类。例如可以控制一个类必须要有文档(参考):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
if class_dic.get('__doc__') is None or \
len(class_dic.get('__doc__').strip()) == 0:
raise TypeError('This class must have docstring!')
if not class_name.istitle():
raise TypeError('First letter in class name should be capitalized!')
super(Mymeta, self).__init__(class_name, class_bases,
class_dic)

class People(object, metaclass=Mymeta):
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('%s is eating' % self.name)

判断一个对象最好的办法是isinstance,因为可以用来处理子类的情况:isinstance(True, int) == True

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SingletonMeta(type):
_instances = {}

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]

class Database(metaclass=SingletonMeta):
def __init__(self, db_conn: str) -> None:
self.db = DBConn(db_conn)

def query(self, sql:str):
session = self.db.create_session()
return session.query(sql)

if __name__ == "__main__":
db = Database("mysql://database")
db.query("SELECT ...")
db = Database("mysql://database")
db.query("SELECT ...")

cpp中关于static的用法说明:

  • 修饰静态成员变量:需要在类外部定义和初始化,因为它们不是在对象被创建时实例化的,而是在程序开始运行时(在进入 main 函数之前)就已经分配好了内存。
  • 修饰静态成员函数:是类的一部分,但它们不依赖于类的特定实例。这意味着它们不能访问类的非静态成员变量或调用非静态成员函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Database {
private:
static Database* pdatabase_;
static std::mutex mutex_;

protected:
Database(const std::string dbconn) : dbconn_(dbconn) {}
~Database() {}
std::string dbconn_;

public:
Database(Database &other) = delete; // =delete表示禁用此函数
void operator=(const Database &) = delete;
static Database* GetInstance(const std::string& dbconn);
ReturnType query(std::string sql) {
// query sql
}
};

// 确保类静态成员在整个生命周期仅初始化一次
Database* Database::pdatabase_{nullptr};
std::mutex Database::mutex_;

Database* Database::GetInstance(const std::string& dbconn) {
// 在这里检查是否要创建一个新的实例
std::lock_guard<std::mutex> lock(mutex_);
if (pdatabase_ == nullptr) pdatabase_ = new Database(dbconn);
return pdatabase_;
}

void ThreadFoo() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Database* db = Database::GetInstance("sql://cool");
std::cout << db->query("SELECT ...") << "\n";
}

void ThreadBar() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
Database* db = Database::GetInstance("sql://another_cool");
std::cout << db->query("SELECT ...") << "\n";
}

int main() {
std::thread t1(ThreadFoo);
std::thread t2(ThreadBar); // should query the same database
t1.join();
t2.join();

return 0;
}