用Python学习一下设计模式,如果很枯燥的话,就强行能使用的就用一下。设计模式参考Python与设计模式-途索

1. 单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

import threading

import time

class Singleton(object):

'''抽象单例'''

def __new__(self, *args, **kw):

if not hasattr(self,'_instance'):

self._instance = super().__new__(self, *args, **kw)

return self._instance

class Bus(Singleton):

'''总线'''

lock = threading.RLock()

def sendData(self, data):

self.lock.acquire()

time.sleep(3)

print("sending signal data... ", data)

self.lock.release()

if __name__ == '__main__':

threadList=[]

for i in range(3):

print("entity %d begin to run ... " % i)

t = threading.Thread(target=Bus().sendData,args=("Entity_"+str(i),))

t.start()

threadList.append(t)

for t in threadList:

t.join()

输出:

entity 0 begin to run ...

entity 1 begin to run ...

entity 2 begin to run ...

sending signal data... Entity_0

sending signal data... Entity_1

sending signal data... Entity_2

看到阿里号发在知乎的一篇设计模式下,有人评论python单例模式直接用模块就可以解决。

Python单例模式没必要弄一个单例类,用一个模块就很好,实例直接作为模块内的全局变量

实战

那模拟一下游戏中组团打BOSS的话,BOSS只实例一次,各个角色攻击或者治疗同一个BOSS。或许之后能成woext的文字小游戏。好吧,就正式命名成WOEXT吧。(wow text,致敬今日开的8.0,期待怀旧服)

import time

class Singleton(object):

'''抽象单例'''

def __new__(self, *args, **kw):

if not hasattr(self,'_instance'):

self._instance = super().__new__(self, *args, **kw)

return self._instance

class Boss(Singleton):

'''BOSS类'''

def __new__(self):

self.hp=100

self._maxHp=100

return super().__new__(self)

def decHp(self,hurt=0):

'''攻击或者治疗'''

if hurt>0:

self.hp-=hurt

self.hp = self.hp if self.hp>0 else 0

elif hurt<0:

self.hp-=hurt

self.hp = self.hp if self.hp

return self.hp

def getHp(self):

return self.hp

class Fighter(object):

'''人物类'''

def __init__(self, name, hp=100, attackVal=10):

self.name=name

#self.hp=hp

#self.attackVal=attackVal

def attack(self, value=0):

b=Boss()

b.decHp(value)

print("{0}| {1} -> boss, {2} {3} . [Boss hp={4}]".format(time.strftime("%M:%S",time.localtime()), self.name,'伤害' if value>=0 else '治疗',abs(value),b.getHp()))

if __name__ == '__main__':

mt=Fighter("哀木涕")

mt.attack(10)

lr=Fighter("劣人")

lr.attack(-3)

dz=Fighter("呆呆贼")

dz.attack(12)

Boss类继承单例类,将hp和 _maxHp属性在__new__中赋值,则拥有了单例属性(唯一、共享)。注:不在super().__new__(self)前赋值的话,则为普通属性。这样还没有赋予抽象单例Singleton太多职责,很单纯的只是实例化。

输出

47:57| 哀木涕 -> boss, 伤害 10 . [Boss hp=90]

47:57| 劣人 -> boss, 治疗 3 . [Boss hp=93]

47:57| 呆呆贼 -> boss, 伤害 12 . [Boss hp=81]

关于Python模块是天然的单例模式。想要实战的话:例子中的打印可以做为战斗日志单独存在,用单例模式(另一个模块文件)实现:

Log.py文件:

class WarLog(object):

'''战斗日志'''

def show(self,message):

print(message)

warLog=WarLog()

导入:

from Log import warLog

和使用(将例子attack()方法中print语句改为):

message="{0}| {1} -> boss, {2} {3} . [Boss hp={4}]".format(time.strftime("%M:%S",time.localtime()), self.name,'伤害' if value>=0 else '治疗',abs(value),b.getHp())

warLog.show(message)

p.s. 想要比较两个实例是否为同一个实例,可用is比较: Boss() is Boss()

pss. 无意发现这么单例之后,Boss 类中不能使用带参数的__init__(self,x)了,卡了半天,有的说2.x到3.x这函数__new__(cls)后面参数没有的,和我这个无关,我的和别人错误不一样的原因是还重载了__new__,就没那么简单了,弄得心烦不弄了,反正只是为了单例属性用了__init__赋值之后也没用。搁置。我可只是为了练一下设计模式的啊,还想早早做出文字MT。

psss. 修正上面pss的备注,

Boss类中__new__, 参数不足。def __new__(self, *args, **kw),即可。但也没有用的。因为

class Boss(Singleton):

'''BOSS类'''

def __new__(self, *args, **kw):

self.hp=100

self._maxHp=100

return super().__new__(self)

def __init__(self,x):

self.o_o=x

pass

a=Boss('a')

b=Boss('b')

print(a.o_o,b.o_o) #输出 b b

这样的话,后面实例的也会覆盖掉之前的。所以init这种事无所谓的。所以,上面的参数我也不改了,不然我这里说这么多就没有意义了(万一别人也会遇到这种难找的错误呢)。上面这段备注都写得混乱,不好意思。

再补充一句,2.x到3.x继承单例之后如果没有重载__new__的话,有TypeError: object() takes no parameters错误,直接改单例中的__new__(cls)参数即可了。

参考

2. 工厂模式

工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

简单工厂模式:省去了将工厂实例化的过程

抽象工厂模式:将每一个细致的产品都建立对应的工厂。 (提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类)

简单工厂模式

# 主食

class Burger():

def __init__(self, name='', price=0.0):

self.name=name

self.price=price

self.type='BURGER'

def getPrice(self):

return self.price

def setPrice(self,price):

self.price=price

def getName(self):

return self.name

class cheeseBurger(Burger):

def __init__(self):

super().__init__("cheese burger", 10.0)

class spicyChickenBurger(Burger):

def __init__(self):

super().__init__("spicy chicken burger", 15.0)

# 小吃

class Snack():

def __init__(self, name='', price=0.0):

self.name=name

self.price=price

self.type='SNACK'

def getPrice(self):

return self.price

def setPrice(self, price):

self.price = price

def getName(self):

return self.name

class chips(Snack):

def __init__(self):

super().__init__("chips", 6.0)

class chickenWings(Snack):

def __init__(self):

super().__init__("chicken wings", 12.0)

# 饮料

class Beverage():

def __init__(self, name='', price=0.0):

self.name=name

self.price=price

self.type='BEVERAGE'

def getPrice(self):

return self.price

def setPrice(self, price):

self.price = price

def getName(self):

return self.name

class coke(Beverage):

def __init__(self):

super().__init__("coke", 4.0)

class milk(Beverage):

def __init__(self):

super().__init__("milk", 5.0)

# 工厂

class SimpleFoodFactory():

'''简单工厂模式'''

@classmethod

def createFood(self,foodClass):

print(" factory produce a instance.")

foodIns=foodClass()

return foodIns

if __name__=="__main__":

cheese_burger=SimpleFoodFactory.createFood(cheeseBurger)

print(cheese_burger.__dict__)

chicken_wings=SimpleFoodFactory.createFood(chickenWings)

print(chicken_wings.__dict__)

coke_drink=SimpleFoodFactory().createFood(coke)

print(coke_drink.__dict__)

输出:

factory produce a instance.

{'name': 'cheese burger', 'price': 10.0, 'type': 'BURGER'}

factory produce a instance.

{'name': 'chicken wings', 'price': 12.0, 'type': 'SNACK'}

factory produce a instance.

{'name': 'coke', 'price': 4.0, 'type': 'BEVERAGE'}

抽象工厂模式

# 青蛙与虫子

class Frog(object):

def __init__(self, name):

self.name = name

def __str__(self):

return self.name

def interact_with(self, obstacle):

print('{} the Frog encounters {} and {}!'.format(self, obstacle, obstacle.action()))

class Bug(object):

def __str__(self):

return 'a bug'

def action(self):

return 'eats it'

class FrogWorld(object):

def __init__(self, name):

print(self)

self.player_name = name

def __str__(self):

return '\n\n\t------ Frog World ------'

def make_character(self):

return Frog(self.player_name)

def make_obstacle(self):

return Bug()

# 术士与兽人

class Wizard(object):

def __init__(self, name):

self.name = name

def __str__(self):

return self.name

def interact_with(self, obstacle):

print('{} the Wizard battles against {} and {}!'.format(

self, obstacle, obstacle.action()))

class Ork(object):

def __str__(self):

return 'an evil ork'

def action(self):

return 'kills it'

class WizardWorld(object):

def __init__(self, name):

print(self)

self.player_name = name

def __str__(self):

return '\n\n\t------ Wizard World ------'

def make_character(self):

return Wizard(self.player_name)

def make_obstacle(self):

return Ork()

class GameEnvironment(object):

'''游戏入口'''

def __init__(self, factory):

self.hero = factory.make_character()

self.obstacle = factory.make_obstacle()

def play(self):

self.hero.interact_with(self.obstacle)

def validate_age(name):

'''年龄检测'''

try:

age = input('Welcome {}. How old are you? '.format(name))

age = int(age)

except ValueError as err:

print("Age {} is invalid, please try again...".format(age))

return (False, age)

return (True, age)

if __name__ == '__main__':

name = input("Hello. What's your name? ")

valid_input = False

while not valid_input:

valid_input, age = validate_age(name)

game = FrogWorld if age < 18 else WizardWorld

environment = GameEnvironment(game(name))

environment.play()

FrogWorld和WizardWorld为抽象工厂。

通过用户年龄判断执行哪个游戏。

输出

Hello. What's your name? cow

Welcome cow. How old are you? 80

------ Wizard World ------

cow the Wizard battles against an evil ork and kills it!

-----------------------------------------------------------

Hello. What's your name? baa

Welcome baa. How old are you? 12

------ Frog World ------

baa the Frog encounters a bug and eats it!

本来看到这个简书的例子看到也是小游戏的还有点小惊喜,运行以后很糟心。不影响运行的字符串里面的单词错误battles和evil, 影响运行的类名GameEnvironment和Frog。就搞不懂了,现在贴代码非要改一些东西才好防伪么?乱七八糟。再从游戏里面吐槽一下,Bug怎么可以有一个方法是eats it,这是自己的方法,抽象出来也应该像++美味风蛇++一样是eat me啊,不考虑这一层也应该是Frog

有一个killing或者Dining方法而Bug有die或者relish方法。

实战

把工厂模式加到之前的WOEXT中。

其实很虚啊,以前刚看Laravel文档不知是被那晦涩的翻译还是文档组织结构还是不太懂的设计模式虐的惨,所以一个设计模式不敢说都懂,现在只是看到工厂模式可以说这是工厂模式,但是用的时候就得理解到底什么是工厂模式了。这就是看懂和实战的区别,也是实战的意义所在。

一个简单工厂模式

import time

from Log import warLog

class Singleton(object):

'''抽象单例'''

def __new__(self, *args, **kw):

if not hasattr(self,'_instance'):

self._instance = super().__new__(self, *args, **kw)

return self._instance

class Boss(Singleton):

'''BOSS类'''

def __new__(self, *args, **kw):

self.hp=100

self._maxHp=100

return super().__new__(self)

def decHp(self,hurt=0):

'''攻击或者治疗'''

if hurt>0:

self.hp-=hurt

self.hp = self.hp if self.hp>0 else 0

elif hurt<0:

self.hp-=hurt

self.hp = self.hp if self.hp

return self.hp

def getHp(self):

return self.hp

class Fighter(object):

'''抽象人物类'''

def __init__(self, name, hp=100, attackVal=10):

self.name=name

self.hp=hp

self.attackVal=attackVal

def attack(self):

value=self.attackVal

b=Boss()

b.decHp(value)

message="{0}| {1} -> boss, {2} {3} . [Boss hp={4}]".format(time.strftime("%M:%S",time.localtime()), self.name,'伤害' if value>=0 else '治疗',abs(value),b.getHp())

warLog.show(message)

class Warrior(Fighter):

'''战士'''

name='战士'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 150, 10)

class Hunter(Fighter):

'''猎人'''

name='猎人'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 100, 8)

class Rogue(Fighter):

'''盗贼'''

name='盗贼'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 80, 12)

class WarFactory(object):

'''战争工厂'''

@classmethod

def createFighter(self, fighter, name=''):

return fighter(name)

if __name__ == '__main__':

zs=WarFactory.createFighter(Warrior, '哀木涕')

zs.attack()

lr=WarFactory.createFighter(Hunter, '劣人')

lr.attack()

dz=WarFactory.createFighter(Rogue, '呆呆贼')

dz.attack()

输出

09:25| 哀木涕 -> boss, 伤害 10 . [Boss hp=90]

09:25| 劣人 -> boss, 伤害 8 . [Boss hp=82]

09:25| 呆呆贼 -> boss, 伤害 12 . [Boss hp=70]

其中,Fighter为抽象的工厂类,Warrior,Hunter,Rogue为具体的工厂类。不过貌似还没有直接创建人物简单呢,那就再补一个场景:需要人海战术打Boss,每个角色只能补一刀。那么调用只需改成:

while Boss().getHp()>0:

r=random.choice([Warrior, Hunter, Rogue])

WarFactory.createFighter(r).attack()

输出:

17:42| 战士 -> boss, 伤害 10 . [Boss hp=90]

17:42| 盗贼 -> boss, 伤害 12 . [Boss hp=78]

17:42| 战士 -> boss, 伤害 10 . [Boss hp=68]

17:42| 猎人 -> boss, 伤害 8 . [Boss hp=60]

17:42| 战士 -> boss, 伤害 10 . [Boss hp=50]

17:42| 猎人 -> boss, 伤害 8 . [Boss hp=42]

17:42| 战士 -> boss, 伤害 10 . [Boss hp=32]

17:42| 盗贼 -> boss, 伤害 12 . [Boss hp=20]

17:42| 猎人 -> boss, 伤害 8 . [Boss hp=12]

17:42| 盗贼 -> boss, 伤害 12 . [Boss hp=0]

当然现在Boss无还手之力,之后加上治疗之类的就会更有意思的。(巴特,我还是不知道自己有没有理解工厂

参考

3. 建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

这个比较好理解啊,就是在一个类中,把需要的模块组合好。真·建造。就不放照抄的代码了,直接实例。

把萨满也加上,让他们四个角色组成一个菊爆小队。

import time

import random

from Log import warLog

class Singleton(object):

'''抽象单例'''

def __new__(self, *args, **kw):

if not hasattr(self,'_instance'):

self._instance = super().__new__(self, *args, **kw)

return self._instance

class Boss(Singleton):

'''BOSS类'''

def __new__(self, *args, **kw):

self.hp=100

self._maxHp=100

return super().__new__(self)

def decHp(self,hurt=0):

'''攻击或者治疗'''

if hurt>0:

self.hp-=hurt

self.hp = self.hp if self.hp>0 else 0

elif hurt<0:

self.hp-=hurt

self.hp = self.hp if self.hp

return self.hp

def getHp(self):

return self.hp

class Fighter(object):

'''抽象人物类'''

def __init__(self, name, hp=100, attackVal=10):

self.name=name

self.hp=hp

self.attackVal=attackVal

def attack(self):

value=self.attackVal

b=Boss()

b.decHp(value)

message="{0} -> boss, {1} {2} . [Boss hp={3}]".format( self.name,'伤害' if value>=0 else '治疗',abs(value),b.getHp())

warLog.show(message)

class Warrior(Fighter):

'''战士'''

name='战士'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 150, 10)

class Hunter(Fighter):

'''猎人'''

name='猎人'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 100, 8)

class Rogue(Fighter):

'''盗贼'''

name='盗贼'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 80, 12)

class Shaman(Fighter):

'''萨满'''

name='萨满'

def __init__(self, name=""):

if name: self.name=str(name)

super().__init__(self.name, 80, 6)

class WarFactory(object):

'''战争工厂'''

@classmethod

def createFighter(self, fighter, name=''):

return fighter(name)

# 建造模式,用来组队

class TeamUp(object):

'''组队(生产)'''

def __init__(self, teamName="小队"):

self.teamName=teamName

self.total=4

self.zs=None

self.ls=None

self.dz=None

self.sm=None

self.team=[]

warLog.show("来人啊,我们{0}要组队了".format(self.teamName))

def enrollment(self, fighter):

'''入队'''

self.team.append(WarFactory.createFighter(fighter))

warLog.show("{0} 入队一人:{1}".format(self.teamName,fighter.name))

def __repr__(self):

if len(self.team)==self.total:

return "{0}成员:{1}, {2}, {3} 以及 {4}。".format(self.teamName,*[a.name for a in self.team])

return "小组不足{0}人".format(self.total)

class TeamDirector(object):

'''组队过程(步骤)'''

def __init__(self, builder):

self.group = builder

def createTeam(self, zs, lr, dz, sm):

'''入队人员'''

self.group.enrollment(zs)

self.group.enrollment(lr)

self.group.enrollment(dz)

self.group.enrollment(sm)

def show(self):

warLog.show(self.group)

if __name__ == '__main__':

# 建造者模式 菊爆小队

team=TeamDirector(TeamUp('【菊爆小队】'))

team.createTeam(Warrior, Hunter, Rogue, Shaman)

team.show()

输出:

19:15:49 来人啊,我们【菊爆小队】要组队了

19:15:49 【菊爆小队】 入队一人:战士

19:15:49 【菊爆小队】 入队一人:猎人

19:15:49 【菊爆小队】 入队一人:盗贼

19:15:49 【菊爆小队】 入队一人:萨满

19:15:49 【菊爆小队】成员:战士, 猎人, 盗贼 以及 萨满。

用到了上节的工厂特性。

4. 原型模式

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象

其实最简单的理解还是Python原型模式这一篇

如果想根据现有对象复制出新的对象并对其修改,可以考虑原型模式

多简单,好娇柔和不造作,和那些妖艳贱货完全不一样。其他文章总是把深浅拷贝拿出来做重点说,其实从原型模式角度只是复制一份对象而已啊,深浅拷贝是其他重点了(我觉得)。修改一下来一个简单的原型模式:

#原型模式

import copy

class Point:

def __init__(self, x, y, l):

print(l)

self.x = x

self.y = y

self.l = l

p1=Point(1,2,[1,2,3])

p2=copy.copy(p1) # 浅拷贝

p3=copy.deepcopy(p1) # 深拷贝

p1.x=0 # 修改 不可改变对象

p1.l.append(4) # 修改(列表)可改变对象 (浅拷贝只会复制原列表的引用,指向同一个对象,所以修改时会更改p2.l)

print(p1, p1.__dict__)

print(p2, p2.__dict__)

print(p3, p3.__dict__)

输出:

[1, 2, 3] #可以看到只执行了一次初始化

<__main__.point object at> {'x': 0, 'y': 2, 'l': [1, 2, 3, 4]}

<__main__.point object at> {'x': 1, 'y': 2, 'l': [1, 2, 3, 4]}

<__main__.point object at> {'x': 1, 'y': 2, 'l': [1, 2, 3]}

这里就没有实例了,太简单了

实战python设计模式_Python与设计模式之创建型模式及实战相关推荐

  1. python创建角色_Python Design Pattern - 4.创建型模式

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2020/11/29 18:06 # @Author : Antenna # @Emai ...

  2. 23种设计模式介绍(一)---- 创建型模式

    由于设计模式篇幅比较大,如果在一篇文章讲完所有的设计模式的话不利于阅读.于是我把它分为三篇文章 23种设计模式介绍(一)---- 创建型模式 23种设计模式介绍(二)---- 结构型模式 23种设计模 ...

  3. 【设计模式】(八)--创建型模式--建造者模式

    [设计模式](八)–创建型模式–建造者模式 建造者模式 [设计模式](八)--创建型模式--建造者模式 建造者模式定义 构造者模式的优点 构造者模式的使用场景 构造者模式和工厂模式区别 构造者模式简单 ...

  4. 【设计模式】三大类:创建型模式、结构型模式、行为型模式

    1 创建型模式 本人理解:以C++为例,创建对象时,用关键字new来创建(实例化)对象.用一个函数或类将new的过程封装起来,就是创建型模式. <设计模式>中的描述: 创建型模式抽象了实例 ...

  5. C#面向对象设计模式纵横谈——Singleton单件(创建型模式)

    Singleton单件(创建型模式) 动机(Motivation) 在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性.以及良好的效率. 如何绕过常规的 ...

  6. .NET设计模式(7):创建型模式专题总结(Creational Pattern)

    概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独立于如何创建.组合和表示它的那些对象.本文对五种常用创建型模式进行了比较,通过一个游戏开发场景的例子来说该如何使用创建型模 ...

  7. 【设计模式】设计模式总结 ( 七大设计原则 | 创建型模式 | 结构型模式 | 行为型模式 ) ★★★

    文章目录 一.七大设计原则 1.开闭原则 2.依赖倒置原则 3.单一职责原则 4.接口隔离原则 5.迪米特原则 6.里氏替换原则 7.合成复用原则 二.创建型模式 0.简单工厂模式 ( 不属于 GOF ...

  8. iOS开发 - 面向对象设计的设计模式(一):创建型模式(附 Demo UML类图)

    继上一篇的面向对象设计的设计原则,本篇是面向对象设计系列的第二个部分:面向对象设计的设计模式的第一篇文章. 另外,本篇博客的代码和类图都保存在我的GitHub库中:中的Chapter2. 最开始说一下 ...

  9. 设计模式学习(二)——创建型模式之“工厂模式“

    常见的创建型模式: 单例模式(手写)--只有一个实例 工厂模式--由对象工厂生成对象 建造者模式--组装复杂的实例 原型模式--通过复制生成实例 一.工厂模式的介绍 1.1.工厂模式的定义 在基类中定 ...

最新文章

  1. Linux命令(基础)
  2. SQL Server数据库中所有表及字段信息
  3. php adodb smarty,smarty+adodb+部分自定义类的php开发模式
  4. 动态性是Java的特性吗_Java的动态特性有哪些?
  5. 基于Python技术栈的算法落地踩坑
  6. robodk导出html错误,在优傲机器人示教器上调试RoboDK机器人程序
  7. 使用 Fluent API 配置/映射属性和类型
  8. centos 6.5 rpm mysql_Linux平台(CentOS 6.5) RPM包方式安装 Mysql 5.7
  9. 肯德基收银系统模式_肯德基的完整形式是什么?
  10. 腾讯视频网页下载_腾讯视频怎么下载视频
  11. HDU 2577(DP)
  12. AndroidStudio_Android使用OkHttp发起Http请求_以及使用时需要注意的点---Android原生开发工作笔记220
  13. [20171113]修改表结构删除列相关问题2.txt
  14. origin拟合曲线,并绘制曲线上某一点的切线
  15. c语言根二的连分数,纯循环连分数 与 二次方程的根
  16. 本题要求计算给定的一系列正整数中奇数的和。
  17. 为何说 a16z 是一家通过 VC 获利的媒体公司?
  18. 无语的index hint:手工分配哈希区,5小时不出结果,优化后20分钟
  19. Java数字转中文大写,数字转英文
  20. MVG读书笔记——单应矩阵估计这件小事(二)

热门文章

  1. python 二维列表(数组)赋值问题
  2. 开发一套pacs系统主要解决的问题有哪些?
  3. 关于Eclipse中XML、JSP、JS等文件打开方式的设置
  4. 115个Java面试题和答案——终极列表
  5. micro api入门
  6. jQuery UI 设计主题
  7. 百度开源绘图工具——echarts的使用
  8. BUUCTF misc------伟大的侦探
  9. 如何将音视频等文件转换成超链接格式
  10. 我对你的思念,如同斐波那契数列,随时间的过去线性递增