目录
- 一、简单工厂模式
- 问题描述
- 模式定义
- 问题分析
- 代码实现
- 二、策略模式
- 问题描述
- 问题分析
- 模式定义
- 代码实现
- 三、装饰模式
- 问题描述
- 问题分析
- 模式定义
- 代码实现
- 四、代理模式
- 问题描述
- 问题分析
- 模式定义
- 代码实现
- 五、工厂方法模式
- 问题描述
- 问题分析
- 模式定义
- 简单工厂 vs. 工厂方法
- 代码实现
一、简单工厂模式
问题描述
小菜今年计算机专业大四了,学了不少软件开发方面的东西,也学着编了些小程序,踌躇满志,一心要找一个好单位。当投递了无数份简历后,终于收到了一个单位的面试通知,小菜欣喜若狂。到了人家单位,前台小姐给了他一份题目,上面写着:"请用C++、Java, C#或VB.NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。
模式定义
简单工厂模式(Simple Factory Pattern)是用一个单独的类来实现具体的实例化过程,避免客户端对具体实例化过程的显式指定。
问题分析
面向对象:封装、继承、多态
简单工厂模式可以用于这个问题。将加减乘除等运算类独立实现,并创建工厂类维护对运算类的使用。之后若需要增加新的运算符号,则只需增加运算类,修改工厂类即可,这也同时降低修改后的重复编译量(松耦合)。此外,简单工厂模式降了低业务逻辑和界面逻辑的耦合,易于复用(不是复制),若未来该windows程序迁移到web版,业务部分(计算部分)不需要修改。
代码实现
class Operation(object):
__numberA = 0
__numberB = 0
def get_numberA(self):
return self.__numberA
def set_numberA(self, numberA):
self.__numberA = numberA
def get_numberB(self):
return self.__numberB
def set_numberB(self, numberB):
self.__numberB = numberB
def get_result(self):
result = 0
return result
numberA = property(get_numberA, set_numberA)
numberB = property(get_numberB, set_numberB)
class OperationAdd(Operation): # 加法类,继承运算类
def get_result(self):
result = self.numberA + self.numberB
return result
class OperationSub(Operation): # 减法类,继承运算类
def get_result(self):
result = self.numberA - self.numberB
return result
class OperationMul(Operation): # 乘法类,继承运算类
def get_result(self):
result = self.numberA * self.numberB
return result
class OperationDiv(Operation): # 除法类,继承运算类
def get_result(self):
if self.numberB == 0:
raise Exception("除数不能为0")
result = self.numberA / self.numberB
return result
class OperationFactory(object): # 简单运算工厂类
def createOperate(self, operate):
if operate == "+":
self.oper = OperationAdd()
elif operate == "-":
self.oper = OperationSub()
elif operate == "*":
self.oper = OperationMul()
elif operate == "/":
self.oper = OperationDiv()
return self.oper
if __name__ == '__main__':
oper = OperationFactory().createOperate("+")
oper.numberA = 1
oper.numberB = 2
result = oper.get_result()
print(result)
二、策略模式
问题描述
小菜,给你出个作业,做一个商场收银软件,营业员根据客户所购买商品的单价和数量,向客户收费。
问题分析
简单工厂模式虽然也能解决这个问题,但这个模式只是解决对象的创建问题,而且由于工厂本身包括了所有的收费方式,商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个工厂,以致代码需重新编译部署,这真的是很糟精的处理方式,所以用它不是最好的办法。面对算法的时常变动,应该有更好的办法。
模式定义
策略模式(Strategy Pattern)是指定义一个算法家族,使得家族内的不同算法都遵从算法家族的接口及方法规范,从而可以实现算法间互相替换,且不会影响到使用算法的客户。
代码实现
import tkinter
import tkinter.ttk
class CashSuper(object): # 现金收取超类的抽象方法,收取现金,参数为原价,返回为当前价
def __init__(self):
pass
def accept_cash(self, money):
pass
class CashNormal(CashSuper): # 正常收费,原价返回
def accept_cash(self, money):
return money
class CashRebate(CashSuper): # 打折收费,初始化时,必需要输入折扣率,如八折,就是0.8
__moneyRebate = 1
def cash_rebate(self, moneyRebateStr):
self.__moneyRebate = float(moneyRebateStr)
def accept_cash(self, money):
return money * self.__moneyRebate
class CashReturn(CashSuper): # 返利收费,初始化时必须要输入返利条件和返利值,比如满300返100,则moneyCondition为300,moneyReturn为100
__moneyCondition = 0
__moneyReturn = 0
def cash_return(self, moneyConditionStr, moneyReturnStr):
self.__moneyCondition = float(moneyConditionStr)
self.__moneyReturn = float(moneyReturnStr)
def accept_cash(self, money):
result = money
if (money >= self.__moneyCondition): # 若大于返利条件,则需要减去返利值
result = money - money // self.__moneyCondition * self.__moneyReturn
return result
class CashContext(object):
def __init__(self, typ):
self.cs = CashSuper()
if typ == "正常收费":
self.cs = CashNormal()
elif typ == "满300返100":
self.cs = CashReturn()
self.cs.cash_return("300", "100")
elif typ == "打8折":
self.cs = CashRebate()
self.cs.cash_rebate("0.8")
def get_result(self, money):
return self.cs.accept_cash(money)
class CashWindow(object):
def __init__(self):
self.total = 0 # 声明一个total来计算总计
root = tkinter.Tk()
self.label1 = tkinter.Label(root, text="单价:")
self.txtPrice = tkinter.Entry(root, width=24, )
self.label2 = tkinter.Label(root, text="数量:")
self.txtNum = tkinter.Entry(root, width=24, )
self.ibxList = tkinter.Text(root, width=45, height=10)
self.label4 = tkinter.Label(root, text="总计:")
self.iblResult = tkinter.StringVar()
self.iblResult.set("%.2f" % self.total) # 保留两位小数的浮点型
self.result = tkinter.Label(root, textvariable=self.iblResult, height=2, font=('TimeNewsRoman', 24))
self.button = tkinter.Button(root, text="确定", width=10, command=self.btnOK_click)
self.buttonReset = tkinter.Button(root, text="重置", width=10, command=self.btnReset_click)
self.label3 = tkinter.Label(root, text="计算方式:")
self.comboVar = tkinter.StringVar()
self.combobox = tkinter.ttk.Combobox(root, textvariable=self.comboVar, width=22, )
self.combobox['value'] = ("正常收费", "打8折", "满300返100") # 在combobox中加下拉选项
self.combobox.current(0)
self.layout()
root.mainloop()
def refresh(self):
self.txtPrice.delete('0', 'end')
self.txtNum.delete('0', 'end')
def layout(self):
self.label1.grid(row=0, column=0, padx=(10, 0), pady=10)
self.txtPrice.grid(row=0, column=1, pady=10, padx=(0, 5), )
self.label2.grid(row=1, column=0, padx=(10, 0))
self.txtNum.grid(row=1, column=1, padx=(0, 5), )
self.label3.grid(row=2, column=0, padx=(10, 0))
self.combobox.grid(row=2, column=1, padx=(0, 5), pady=10)
self.ibxList.grid(row=4, column=0, columnspan=4, padx=(5, 5), pady=10)
self.label4.grid(row=5, column=0, padx=(10, 0))
self.result.grid(row=5, column=1, columnspan=3, rowspan=2)
self.button.grid(row=0, column=2, columnspan=2, pady=10, padx=(0, 10))
self.buttonReset.grid(row=1, column=2, columnspan=2, padx=(0, 10))
def btnReset_click(self):
self.total = 0
self.ibxList.delete('1.0', 'end')
self.iblResult.set("%.2f" % self.total)
self.refresh()
# 主要部分
def btnOK_click(self):
csuper = CashContext(self.comboVar.get())
totalPrice = csuper.get_result(
float(self.txtPrice.get()) * float(self.txtNum.get())) # 声明一个totalPrice来计算每个商品的单价(txtPrice)*数量(txtNum)后的合计
self.total = self.total + totalPrice # 将每个商品合计计入总计
self.ibxList.insert('end',
"单价:" + self.txtPrice.get() + "数量:" + self.txtNum.get() + " " + self.comboVar.get() + "合计:%.2f" % (
totalPrice) + "\n") # 在列表框中显示信息
self.iblResult.set("%.2f" % self.total)
self.refresh()
if __name__ == '__main__':
CashWindow()
三、装饰模式
问题描述
我现在要求你写一个可以给人搭配不同的服饰的系统,比如类似QQ、网络游戏或论坛都有的Avatar系统。你怎么开发?
问题分析
建造者模式要求建造的过程必须是稳定的,而现在我们这个例子,建造过程是不稳定的,比如完全可以内穿西装,外套T恤,再加披风,打上领带,皮鞋外再穿上破球鞋:当然也完全可以只穿条辫衩就算完成。换句话就是说,通过服饰组合出一个有个性的人完全可以有无数种方案,并非是固定的。我们需要把所需的功能按正确的顺序串联起来进行控制,此时可以考虑使用装饰模式。
模式定义
装饰模式(Decorator Pattern)是指创建一个装饰类,来包装原有的类,从而实现动态地向一个现有的对象添加一些额外的职责,同时不改变其原有的结构。装饰模式比生成子类更为灵活。
代码实现
class Person(object):
def __init__(self, name=""):
self.name = name
def show(self):
print("装扮的" + self.name)
# 服饰类(Decorator)
class Finery(Person):
component = None
def decorate(self, component: Person):
self.component = component
def show(self):
if self.component != None:
self.component.show()
# 具体服饰类(Concrete Decorator)
class Tshirts(Finery):
def show(self):
print("大T恤", end=" ")
super().show()
class BigTrouser(Finery):
def show(self):
print("垮裤", end=" ")
super().show()
class Sneakers(Finery):
def show(self):
print("破球鞋", end=" ")
super().show()
class Suit(Finery):
def show(self):
print("西装", end=" ")
super().show()
class Tie(Finery):
def show(self):
print("领带", end=" ")
super().show()
class LeatherShoes(Finery):
def show(self):
print("皮鞋", end=" ")
super().show()
if __name__ == '__main__':
xc = Person('小菜')
print("第一种装扮:")
dtx = Tshirts()
kk = BigTrouser()
pqx = Sneakers()
pqx.decorate(xc)
kk.decorate(pqx)
dtx.decorate(kk)
dtx.show()
print("第二种装扮:")
xz = Suit()
ld = Tie()
px = LeatherShoes()
px.decorate(xc)
ld.decorate(px)
xz.decorate(ld)
xz.show()
print("第三种装扮:")
pqx2 = Sneakers()
px2 = LeatherShoes()
kk2 = BigTrouser()
ld2 = Tie()
pqx2.decorate(xc)
px2.decorate(pqx2)
kk2.decorate(px2)
ld2.decorate(kk2)
ld2.show()
四、代理模式
问题描述
隔壁班的卓贾易想追求娇娇,但是他自己不好意思,就委托和娇娇同班的戴励帮助他。
问题分析
模式定义
代理模式(Proxy Pattern)是指实现一个类代表另一个类的功能,为其他对象提供一种代理以控制对这个对象的访问。
- 第一,远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
- 第二种应用是虚拟代理,是根据需要创建开销很大的对象.通过它来存放实例化需要很长时间的真实对象。
- 第三种应用是安全代理,用来控制真实对象访问时的权限[DP],一般用于对象应该有不同的访问权限的时候。第四种是智能指引,是指当调用真实的对象时,代理处理另外一些事。
代码实现
class SchoolGirl(object):
__name = None
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
name = property(get_name, set_name)
class IGiveGift(object):
def give_dolls(self):
pass
def give_flowers(self):
pass
def give_chocolate(self):
pass
class Pursuit(IGiveGift):
__mm = None
def __init__(self, mm: SchoolGirl):
self.__mm = mm
def give_dolls(self):
print(self.__mm.name + " 送你洋娃娃")
def give_flowers(self):
print(self.__mm.name + " 送你鲜花")
def give_chocolate(self):
print(self.__mm.name + " 送你巧克力")
class Proxy(IGiveGift):
def __init__(self, mm: SchoolGirl):
self.gg = Pursuit(mm)
def give_dolls(self):
self.gg.give_dolls()
def give_flowers(self):
self.gg.give_flowers()
def give_chocolate(self):
self.gg.give_chocolate()
if __name__ == '__main__':
jiaojiao = SchoolGirl()
jiaojiao.name = "李娇娇"
daili = Proxy(jiaojiao)
daili.give_dolls()
daili.give_flowers()
daili.give_chocolate()
五、工厂方法模式
问题描述
大学生薛磊风在过去三年里一直在帮助孤寡老人,每周都去老人家里,为老人洗衣扫地、买米买油。有一次,他不幸受了伤,便委托他的两个同学继续去帮助老人,且不必提及任何人的名字,只需说是学雷锋做好事即可。
帮助老人是长期工作,三名“学雷锋的大学生”毕业后,也依然会以“社区志愿者”的名义继续学雷锋做好事。而老人其实不需要知道是谁来做好事,只需要知道是学雷锋的人来帮助就可以了。
问题分析
这一程序可以先用简单工厂模式
实现,但由于学雷锋的学生毕业后,会转变身份成为社区志愿者,此时若使用简单工厂模式会涉及到工厂类的修改,违背开放封闭原则。当我们使用工厂方法模式
时,可以对学雷锋的学生和社区志愿者分别建立工厂类,让客户端决定实例化哪一个工厂类。
模式定义
工厂方法模式(Factory Method Pattern)是指定义一个用于创建对象的结构,让子类决定实例化哪个类。工厂方法使类的实例化过程延迟到其子类。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现功能类,即将简单工厂内部的逻辑判断已到了客户端进行。
简单工厂 vs. 工厂方法
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对干客户端来说,去除了与具体产品的依赖。工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
代码实现
class LeiFeng(object):
def sweep(self):
print("扫地")
def wash(self):
print("洗衣")
def buy_rice(self):
print("买米")
class Undergraduate(LeiFeng):
pass
class Volunteer(LeiFeng):
pass
class SimpleFactory(object):
def create_LeiFeng(self, typ: str) -> LeiFeng:
self.result = None
if typ == "学雷锋的大学生":
self.result = Undergraduate()
elif typ == "社区志愿者":
self.result = Volunteer()
return self.result
class IFactory(object):
def create_LeiFeng(self):
pass
class UndergraduateFactory(IFactory):
def create_LeiFeng(self):
return Undergraduate()
class VolunteerFactory(IFactory):
def create_LeiFeng(self):
return Volunteer()
if __name__ == '__main__':
# 简单工厂模式
studentA = SimpleFactory().create_LeiFeng("学雷锋的大学生")
studentA.buy_rice()
studentB = SimpleFactory().create_LeiFeng("学雷锋的大学生")
studentB.sweep()
studentC = SimpleFactory().create_LeiFeng("学雷锋的大学生")
studentC.wash()
# 工厂方法模式
factory = UndergraduateFactory()
student = factory.create_LeiFeng()
student.buy_rice()
student.sweep()
student.wash()
factory = VolunteerFactory()
student = factory.create_LeiFeng()
student.buy_rice()
student.sweep()
student.wash()
学习参考链接:
视频1: https://www.bilibili.com/video/BV1hG4y1d7GK?p=4&vd_source=c5d53beb52dbf1f3fcc4518fb4b1cbfa
视频2: https://www.bilibili.com/video/BV1454y187Er/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=c5d53beb52dbf1f3fcc4518fb4b1cbfa