Python亨元模式介绍、使用

一、Python亨元模式介绍

概念:

        享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建对象的数量,以提高应用程序的性能。享元模式通过共享尽可能多的数据来减少内存使用。

功能: 享元模式的主要功能是节省内存。

优点:

  1. 减少内存使用。
  2. 提高程序性能。
  3. 对象共享可以降低程序的复杂度。

缺点:

  1. 可能会导致代码复杂性增加。
  2. 缓存的数据可能过多,导致需要更多的内存。

应用场景:

  1. 有大量的相似对象需要创建。
  2. 对象的大部分属性可以共享,相对稳定。
  3. 需要缓存数据的应用程序。

使用方式:

  1. 定义一个工厂类,用于创建享元对象。
  2. 定义享元对象接口。
  3. 实现享元对象的具体类。
  4. 在工厂类中按照需要维护享元对象的池子,以便重用对象。
  5. 在客户端中使用享元对象。

在应用程序开发中的应用:

  1. 网络编程中,可以使用享元模式来管理连接池。
  2. 图像处理中,可以使用享元模式来缓存图像对象,以提高程序性能。
  3. 对于需要创建大量相似对象的应用程序,可以使用享元模式来减少内存使用。

二、亨元模式使用

工作原理:

         享元模式的工作原理是通过共享尽可能多的数据来减少内存使用。

在享元模式中,创建对象的过程被分为两个阶段。

  1. 第一阶段,创建对象并初始化所有属性。
  2. 第二阶段,所有属性被设置为共享属性,以便在创建其他对象时可以共享这些属性。

通过这种方式,一个对象可以通过多次使用相同的属性来减少内存使用。

示例一:亨元模式创建相似对象的应用程序

        我们以一个图书馆管理系统为例,假设在该系统中有成千上万本书籍,而这些书籍中大部分属性都是相同的,例如书名、作者、出版社等信息,只有少部分属性是不同的,例如ISBN编码、出版日期等信息。如果我们为每本书都创建一个独立的对象,将会占用大量的内存,因此应该考虑使用享元模式来管理这些对象。

首先,我们需要定义一个 Book 接口,以便创建书籍对象,并在接口中定义书籍属性的方法:

接着,我们定义一个具体的书籍类 BookImpl,用于实现 Book 接口:

接下来,我们定义一个书籍工厂类 BookFactory,用于创建和管理书籍对象:

最后,我们在客户端代码中,使用 BookFactory 来创建和获取书籍对象:

from abc import ABC,abstractmethod

# ***************************************************************************使用亨元模式 创建大量相似对象的应用程序,减少内存使用
class Book(ABC):
    '''
    书籍接口,定义书籍属性 书名、作者、出版社
    '''
    @abstractmethod
    def get_book_name(self):
        pass

    @abstractmethod
    def get_book_author(self):
        pass

    @abstractmethod
    def get_book_publisher(self):
        pass

class BookImpl(Book):
    '''
    定义具体书籍类,实现Book方法
    '''
    def __init__(self, name, author, publisher):
        self.name = name
        self.author = author
        self.publisher = publisher
    def get_book_name(self):
        return self.name
    def get_book_author(self):
        return self.author
    def get_book_publisher(self):
        return self.publisher

class BookFactory():
    '''
    定义书籍工厂类,用于创建和管理书籍对象
    '''
    def __init__(self):
        self.books = {}

    def get_book(self, name, author, publisher):
        '''
        创建书籍对象,已存在相同属性的书籍对象,直接返回已有对象
        '''
        if (name, author, publisher) not in self.books:
            # 判断不存在相同的属性,将新的书籍添加到池子中
            self.books[(name, author, publisher)] = BookImpl(name, author, publisher)
        return self.books[(name, author, publisher)]

# 创建书籍工厂对象
fac = BookFactory()
# 获取书籍
book1 = fac.get_book("book1", "author1", "pub1")
book2 = fac.get_book("book2", "author2", "pub2")
book3 = fac.get_book("book3", "author3", "pub3")
# 打印书籍信息
print(book1.get_book_name(), book1.get_book_author(), book1.get_book_publisher())
print(book2.get_book_name())
print(book3.get_book_name())

运行结果:

book1 author1 pub1
book2
book3

在上面的代码中,我们创建了三本书籍对象,并打印了它们的属性。在创建书籍对象时,我们使用了 BookFactory 来管理书籍对象的池子,以便重用已经存在的对象。通过共享相同属性的对象,我们可以减少内存的使用,提高程序的性能。

示例二:享元模式实现管理ssh连接池功能

        在实际应用中,享元模式通常用于管理大量的共享对象,例如线程池、连接池等。下面我们以连接池为例,来说明如何使用 Python 实现连接池的功能。

连接池是一种常见的数据库连接管理方式。在传统的数据库连接方式中,每次需要连接数据库时,都会重新创建一个数据库连接对象。这样会消耗大量的系统资源,并且每次创建连接对象都需要进行一系列的初始化工作,导致连接对象的创建速度比较缓慢。而使用连接池,则可以通过共享连接对象来提高程序的性能。

首先,我们需要定义一个数据库连接池 ConnectionPool 类,其中包含两个方法:init() 方法用于初始化连接池对象,create_connection() 方法用于创建数据库连接对象。

其中,max_connections 参数表示连接池中最大的连接数,如果连接池中已经存在 max_connections 个连接对象,则直接返回第一个连接对象。如果连接池中的连接对象不足 max_connections 个,则创建一个新的连接对象,并添加到连接池中。

接下来,我们在客户端代码中,通过 ConnectionPool 来获取连接对象:

import paramiko

class SSHConnectionPool():
    '''
    SSH 连接池
    '''
    def __init__(self, host, port, username, password, max_connection = 10):
        # 初始化连接池对象
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.max_connection = max_connection
        self.connections = []

    def create_connection(self):
        # 创建ssh对象
        if len(self.connections) < self.max_connection:
            conn = paramiko.SSHClient()
            conn.set_missing_host_key_policy(paramiko.AutoAddPolicy)
            conn.connect(self.host, self.port, self.username, self.password)
            self.connections.append(conn)
        else:
            conn = self.connections.pop(0)
        return conn

# 创建连接池对象
pool = SSHConnectionPool(host="192.168.1.***", port=22, username="root", password="123456")

# 获取SSH连接对象
conn1 = pool.create_connection()
conn2 = pool.create_connection()
conn3 = pool.create_connection()

# 执行命令
stdin, stdout, stderr = conn1.exec_command("ls")
print(stdout.readlines())

# 关闭连接
conn1.close()
conn2.close()
conn3.close()

运行结果:

['anaconda-ks.cfg\n', 'Desktop\n', 'Documents\n', 'Downloads\n', 'ifconfig_20230607.txt\n', 'initial-setup-ks.cfg\n', 'kmod-r8125-9.003.05-1.el7_8.elrepo.x86_64.rpm\n', 'Music\n', 'Pictures\n', 'Public\n', 'Templates\n', 'test\n', 'Videos\n']
 

在上面的代码中,我们创建了一个连接池对象 pool,并获取了三个连接对象 conn1、conn2、conn3。通过连接对象获取游标对象,并执行 SQL 语句。最后,我们将连接对象关闭,并释放资源。

使用连接池可以有效地减少数据库连接的创建和销毁过程,减少系统资源的占用,提高程序的性能。

猜你喜欢

转载自blog.csdn.net/songpeiying/article/details/131923963