Posts 设计模式-对象池技术
Post
Cancel

设计模式-对象池技术

概念解析

对象池技术,指的是设计一个集合,其中包含了初始化且可以使用的对象,当需要使用相关对象时,直接从中获取,且使用完后需要归还。与前置“享元模式”的区别在于,享元模式没有“占用”的概念,享元对象都是共享的,而对象池中的对象则在“借出”期间是被独占的,可以修改对象的部分属性,而享元独享的属性通常无法被更改。 对象池的两个核心对象:

  • 要进行的池化对象:通常是创建和销毁比较耗时,或者本身比较占内存的对象
  • 对象池:对象集合,或者管理器,用于管理对象的借用、归还

其优点在于:

  • 实现了对象的重复使用,减少内存占用,提升程序性能

缺点在于:

  • 借用和归还操作需要成对出现,不然会出现一直占用的情况
  • 错误对已归还的对象引用可能引发问题

对象池技术应用非常广泛,Python的“引用计数”思想便是对象池计数的运用,另外如Java的Commons-pool,C++的智能指针等,其他应用如数据库连接池、线程池等。

设计模板

对象池机制的框架模型如下:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from abc import ABCMeta, abstractmethod
import logging
import time
logging.basicConfig(level=logging.INFO)


class PooledObject():
    """池化对象"""
    def __init__(self, obj):
        self.__obj = obj
        self.__busy = False

    def get_object(self):
        return self.__obj

    def set_object(self, obj):
        self.__obj = obj

    def is_busy(self):
        return self.__busy

    def set_busy(self, busy):
        self.__busy = busy


class ObjectPool(metaclass=ABCMeta):
    """对象池"""

    # 初始化参数
    initial_num_of_objects = 0
    max_num_of_objects = 50

    def __init__(self):
        self.__pools = []
        for i in range(0, ObjectPool.initial_num_of_objects):
            obj = self.create_pooled_object()
            self.__pools.append(obj)

    @abstractmethod
    def create_pooled_object(self):
        """创建池对象,由子类实现该方法"""
        pass

    def borrow_object(self):
        """借用对象"""
        # 如果找到空闲对象,直接返回
        obj = self.__find_free_object()
        if obj is not None:
            logging.info("%x 对象已被借用,time:%s", id(obj),
                         time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))

            return obj
        # 对象池未满,则添加新的对象
        if len(self.__pools < ObjectPool.max_num_of_objects):
            pooled_obj = self.add_object()
            if pooled_obj is not None:
                pooled_obj.set_busy()
                logging.info("%x 对象已被借用,time:%s", id(obj),
                             time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
                return pooled_obj.get_object()
        # 对象池已满且没有空闲对象,返回None
        return None

    def return_object(self, obj):
        """归还对象"""
        for pooled_obj in self.__pools:
            if pooled_obj.get_object() == obj:
                pooled_obj.set_busy(False)
                logging.info("%x 对象已被归还,time:%s", id(obj),
                             time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))

    def add_object(self):
        """添加新对象"""
        obj = None
        if (len(self.__pools) < ObjectPool.max_num_of_objects):
            obj = self.create_pooled_object()
            self.__pools.append(obj)
            logging.info("添加新对象%x,time:%s", id(obj),
                         time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
            return obj

    def clear(self):
        """清空对象池"""
        self.__pools.clear()

    def _find_free_object():
        """查找空闲的对象"""
        obj = None
        for pooled_obj in self.__pools:
            if not pooled_obj.is_busy():
                obj = pooled_obj.get_object()
                pooled_obj.set_busy(True)
                break
        return obj

实例分析

场景分析:设计共享充电宝的借用机制

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class  PowerBank():
    """移动电源"""

    def __init__(self, serial_num, electric_quantity):
        self.__serial_num = serial_num
        self.__electric_quantity = electric_quantity
        self.__user = ""

    def get_serial_num(self):
        return self.__serial_num

    def get_electric_quantity(self):
        return self.__electric_quantity

    def set_user(self, user):
        self.__user = user

    def get_user(self):
        return self.__user

    def show_info(self):
        print("序列号:%03d 电量:%d%% 使用者:%s" %
              (self.__serial_num, self.__electric_quantity, self.__user))


class PowerBankPool(ObjectPool):
    """存放移动电源的智能箱盒"""

    __serial_num = 0

    @classmethod
    def get_serial_num(cls):
        cls.__serial_num += 1
        return cls.__serial_num

    def create_pooled_object(self):
        power_bank = PowerBank(PowerBankPool.get_serial_num(), 100)
        return PooledObject(power_bank)


def test_object_pool():
    power_bank_pool = PowerBankPool()
    powerbank1 = power_bank_pool.borrow_object()
    if powerbank1 is not None:
        powerbank1.set_user("Tony")
        powerbank1.show_info()

    powerbank2 = power_bank_pool.borrow_object()
    if powerbank2 is not None:
        powerbank2.set_user("Sam")
        powerbank2.show_info()

    power_bank_pool.return_object(powerbank1)
    powerbank3 = power_bank_pool.borrow_object()
    if powerbank3 is not None:
        powerbank3.set_user("Aimee")
        powerbank3.show_info()

    power_bank_pool.return_object(powerbank2)
    power_bank_pool.return_object(powerbank3)
    power_bank_pool.clear()
    """
    测试结果:
    INFO:root:1111对象已被借用,time:yyyy-yy-yy yy:yy:yy
    序列号:001 电量:100% 使用者:Tony
    INFO:root:2222对象已被借用,time:yyyy-yy-yy yy:yy:yy
    序列号:002 电量:100% 使用者:Sam
    INFO: root:1111对象已归还,time:yyyy-yy-yy yy:yy:yy
    INFO:root:3333对象已被借用,time:yyyy-yy-yy yy:yy:yy
    序列号:003 电量:100% 使用者:Aimee
    INFO: root:2222对象已归还,time:yyyy-yy-yy yy:yy:yy
    INFO: root:3333对象已归还,time:yyyy-yy-yy yy:yy:yy
    """
This post is licensed under CC BY 4.0 by the author.

设计模式-过滤器模式

设计模式-回调机制