python设计模式(一)

python设计模式

面向对象核心概念

对象

他们表示所开发的应用程序内的实体

实体之间可以通过交互来解决现实中的问题

帮助开发人员表示现实世界中的实体

类可以定义对象的属性和行为,属性是数据成员,行为由成员函数表示。

类包含了构造函数,这些函数的作用是为对象提供初始状态

类就像模版一样,非常易于重复使用。

方法

表示对象的行为。

对属性进行处理,从而实现所需的功能。

封装

对象的行为对于外部世界来说是不可见的,或者说对象的状态信息是私密的。

客户端不能通过直接操作来改变对象的内部状态,相反,客户端需要通过发送消息来请求对象来改变其内部状态。对象可以根据请求的类型,通过特定的成员函数(例如get,set)来改变他们的内部状态,以做出相应的响应。

在py中,封装的概念不是隐式的,它没有提供封装所需的关键字。在变量或函数名前面加上前缀_,就可以将其访问性变为私有。

多态

两种类型:

  • 对象根据输入参数提供方法的不同实现
  • 不同类型的对象可以使用相同的接口

对于py,多态是内置功能。

继承

继承表示一个类可以继承父类的功能。

继承被描述为一个重用基类中定义的功能并允许对原始软件的实现进行独立扩展的选项。

继承可以利用不同类的对象之间的关系建立层次结构。与Java不同,py支持多重继承。

抽象

提供一个简单的客户端接口,客户端可以通过该接口与类的对象进行交互,并可以调用该接口中定义的各个方法。

它将内部类的复杂性抽象为一个接口,这样客户端就不需要知道内部实现。

组合

它是一种将对象或类组合成更复杂的数据结构或软件实现的方法。

一个对象可用于调用其它模块中的成员函数,无需通过继承就能实现基本功能的跨模块使用了。

设计原则

开放/封闭原则

类或对象及其方法对于扩展来说,应该是开放的,对于修改来说应该是封闭的。

优点:现有的类不会被修改,退化的可能性小

有助于保持以前代码的向后兼容性

控制反转原则

高层级的模块不应该依赖于底层级的模块,他们都应该依赖于抽象。细节应该依赖于抽象,而不是抽象依赖于细节。

优点:消弱了模块间的紧耦合,因此消除了系统中的复杂性/刚性。

在依赖模块中有一个明确的抽象层,便于通过更好的方式处理模块之间的依赖关系。

接口隔离原则

客户端不应该依赖于他们不需要使用的接口。

优点 : 强制开发人员编写“瘦身型”接口,并使用方法与接口紧密相关。

防止向接口中随意添加方法。

单一职责原则

类的职责是单一的,引起类变化的原因是单一。

优点:每当一个功能发生变化时,除了特定的类需要改变外。其他类无需变动。

此外,如果一个类有多种功能,那么依赖它的类必定会由于多种原因而经历多次修改,这是应该避免的。

替换原则

派生类必须能共完全取代基类。

设计模式的概念

主要特点:

  • 与语言无关,可以用多种语言实现 (huchi不认同)
  • 他们是动态的,随时会有新的模式引入
  • 可以进行定制

优点

  • 可以在多个项目中重复使用
  • 问题可以在架构级别得到解决
  • 经过时间的验证和良好的证明
  • 具有可靠性和依赖性

分类

  • 代码段:用某种语言编写的一段具有特定用途的代码
  • 设计:用来解决某个特定问题的优秀解决方案
  • 标准:这是一种解决某类问题的方法,通用。
  • 模式:一个经过时间考研、高效、可扩展的解决方案。

上下文

  • 参与者:他们是在设计模式中用到的类。类 可以在模式中扮演不同的角色,以完成不同的目标
  • 非功能需求:如内存优化、可用性和性能等需求都属于此类型。影响整个软件的解决方案,至关重要。
  • 权衡:并非所有的设计模式都是用与应用程序开发。
  • 结果:山下文不合适,设计模式可能对代码的其他部分造成负面影响。

模式的分类

主要 分为三类

  1. 创建型模式
    • 运行机制基于对象的创建方式
    • 将对象创建的细节隔离
    • 代码与所创建的对象的类型无关
  2. 结构型模式
    • 致力于设计出能够通过组合获得强大功能的对象和类的结构
    • 重点是简化结构并识别类和对象之间的关系
    • 主体要关注类的继承和组合
  3. 行为型模式
    • 关注对象之间的交互以及对象的响应性
    • 对象应该能够交互,同时保持松散耦合。

单例设计模式

​ 意图:

  • 确保类有且只有一个对象被创建。
  • 为对象提供一个访问点,以使程序可以全局访问该对象
  • 控制共享资源的并行访问。

实现的简单方法,使构造器私有化,并创建一个静态方法来完成对象的初始化。(python有所变通)

1
2
3
4
5
6
7
8
9
10
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance

s = Singleton()
print(s)
s1 = Singleton()
print(s1)

我们创建两次Singleton发现地址相同

懒汉式

仅在需要的时候才创建他们

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton:
__instance = None
def __init__(self):
if not Singleton.__instance:
print("__init__ method called ...")
else:
print("Instance already created:", self.__instance)

@classmethod
def getInstance(cls):
if not cls.__instance:
cls.__instance = Singleton()
return cls.__instance

默认情况下所有模块都是单例模式。

Monostate(单态)单例模式

1
2
3
4
5
6
7
8
9
10
11
class Borg:
__shared_state = {'1':'2'}
def __init__(self):
self.__dict__ = self.__shared_state # __dict__存储所有对象的状态
pass

b = Borg()
b1 = Borg()
b.x = 4
print(b,b1)
print(b1.x)

虽然可以创建了不同的实例,但是他们拥有状态是一样的,都是__shared_state里面的东西。

单例和元类

元类是一个类的类。也就是意味着一个类是这个元类的实例。类的定义由他的元类来决定。py通过A = type(name, bases, dict)创建它。几个变量名分别代表着类的名称,基类,属性变量。

1
2
3
4
5
6
7
8
9
10
11
12
class HuchiInt(type):
def __call__(cls, *args, **kwargs):
print("Huchi's int",args)
return type.__call__(cls, *args, **kwargs)

class int(metaclass=HuchiInt):
def __init__(self,x ,y):
self.x = x
self.y = y

i = int(1, 2)
print(i)

可以看到元类控制着对象的实例化,元类对类创建和对象实例化有更多的控制权,可以用于创建单例(为了控制类的创建和初始化,元类将覆盖__init__和__new__方法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
class MetaSingleton(type):
_instance = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instance:
cls._instance[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instance[cls]

class Logger(metaclass=MetaSingleton):
pass

logger1 = Logger()
logger2 = Logger()
print(logger1, logger2)

每个产生的类都有_instance。

单例模式I

数据库:

多次实例化也只有一个对象,避免消耗过多的内存和CPU资源,但是面对多个web应用共享单个数据库的话,每增加一个应用程序就要新建一个单例,添加一个新的对象来访问数据库,导致数据库操作无法同步,不如数据库连接池好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sqlite3
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]

class Database(metaclass=MetaSingleton):
connection = None
def connect(self):
if self.connection is None:
self.connection = sqlite3.connect("db.sqlite3")
self.cursorobj = self.connection.cursor()
return self.cursorobj

db1 = Database().connect()
db2 = Database().connect()
print(db1, db2)

单例模式II

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
from random import random
class HealthCheck:
_instance = None
def __new__(cls, *args, **kwargs):
if not HealthCheck._instance:
HealthCheck._instance = super(HealthCheck, cls).__new__(cls, *args, **kwargs)
return HealthCheck._instance

def __init__(self):
self._servers = []

def addSever(self, str):
self._servers.append(str)

def changeServer(self, str):
if len(self._servers) > 0:
self._servers.pop()
self._servers.append(str(random()))

huchi1 = HealthCheck()
huchi2 = HealthCheck()

huchi1.addSever('huchi1')
huchi1.addSever('huchi2')
print(huchi1,huchi2)
for i in huchi2._servers:
print(i, end=' ')

单例模式的缺点

由于具有全局访问权限,可能会出现以下问题

  • 全局变量可能在某处已经被误改,但仍然在应用程序中的其他位置使用
  • 可能会对同一个对象创建多个引用。
  • 所有依赖于全局变量的类都会有一个类的改变而紧密耦合为全局数据,从而在无意中影响到另一个类
文章目录
  1. 1. python设计模式
    1. 1.1. 面向对象核心概念
      1. 1.1.1. 设计原则
      2. 1.1.2. 设计模式的概念
        1. 1.1.2.1. 优点
        2. 1.1.2.2. 分类
        3. 1.1.2.3. 上下文
        4. 1.1.2.4. 模式的分类
  2. 2. 单例设计模式
    1. 2.1. 单例和元类
    2. 2.2. 单例模式I
    3. 2.3. 单例模式II
    4. 2.4. 单例模式的缺点
|