AI越来越火热,人工智能已然成风!而人工智能最重要是各种算法,因此机器学习越来越受到追捧,算法越来越被重视。
作为一个算法的研究者,写出一手高级算法当然是令人兴奋的一件事!但你是否有时会有这种感觉:
这个时候,让你的算法具有更好通用性、拓展性就显得极为重要!因此,你必须要掌握几个重要的设计模式来优化你的代码,解决这些问题。今天就来聊聊那些专为算法设计的模式:策略模式、模板方法模式、访问模式。
封装一些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问模式的核心思想在于:可以在不改变数据结构的前提下定义作用于这些元素的新操作。将数据结构和具体算法进行解耦,而且能更方便地拓展新的操作。
from abc import ABCMeta, abstractmethod
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
class DataNode(metaclass=ABCMeta):
"数据结构类"
def accept(self, visitor):
"接受访问者的访问"
visitor.visit(self)
class Visitor(metaclass=ABCMeta):
"访问者"
@abstractmethod
def visit(self, data):
"对数据对象的访问操作"
pass
class ObjectStructure:
"数据结构的管理类,也是数据对象的一个容器,可遍历容器内的所有元素"
def __init__(self):
self.__datas = []
def add(self, dataElement):
self.__datas.append(dataElement)
def action(self, visitor):
"进行数据访问的操作"
for data in self.__datas:
visitor.visit(data)
这里Visitor的访问方法只有一个visit(),是因为Python不支持方法的重载。在一些强类型的语言(如Java、C++)中,应该有多个方法,针对每一个DataNode子类定义一个重载方法。
DataNode是数据结点,可接受(accept)访问者的访问,DataNodeA和DataNodeB是它的具体实现类。Visitor是访问者类,可访问(visit)具体的对象。ObjectStructure是数据结构的管理类,也是数据对象的一个容器,可遍历容器内的所有元素。
在宠物界中,猫和狗历来就是一对欢喜冤家!假设宠物店中有N只猫和M只狗。我们要进行下面这3个操作:
这个时候,如果要在猫和狗的对象上添加这些操作,将会增加非常多的方法而污染原有的对象;而且这些操作的拓展性也将非常差。这时访问模式是解决这个问题的最好方法,我们一起看一下具体的实现如下:
源码示例:
class Animal(DataNode):
"""动物类"""
def __init__(self, isMale, weight):
self.__isMale = isMale
self.__weight = weight
def isMale(self):
return self.__isMale
def getWeight(self):
return self.__weight
class Cat(Animal):
"""猫"""
def speak(self):
print("miao~")
class Dog(Animal):
"""狗"""
def speak(self):
print("wang~")
class GenderCounter(Visitor):
"""性别统计"""
def __init__(self):
self.__maleCat = 0
self.__femaleCat = 0
self.__maleDog = 0
self.__femalDog = 0
def visit(self, data):
if isinstance(data, Cat):
if data.isMale():
self.__maleCat += 1
else:
self.__femaleCat += 1
elif isinstance(data, Dog):
if data.isMale():
self.__maleDog += 1
else:
self.__femalDog += 1
else:
print("Not support this type")
def getInfo(self):
print(str(self.__maleCat) + "只雄猫," + str(self.__femaleCat) + "只雌猫,"
+ str(self.__maleDog) + "只雄狗," + str(self.__femalDog) + "只雌狗。")
class WeightCounter(Visitor):
"""体重的统计"""
def __init__(self):
self.__catNum = 0
self.__catWeight = 0
self.__dogNum = 0
self.__dogWeight = 0
def visit(self, data):
if isinstance(data, Cat):
self.__catNum +=1
self.__catWeight += data.getWeight()
elif isinstance(data, Dog):
self.__dogNum += 1
self.__dogWeight += data.getWeight()
else:
print("Not support this type")
def getInfo(self):
print("猫的平均体重是:%0.2fkg, 狗的平均体重是:%0.2fkg" %
((self.__catWeight / self.__catNum),(self.__dogWeight / self.__dogNum)))
测试代码:
def testAnimal():
animals = ObjectStructure()
animals.add(Cat(True, 5.1))
animals.add(Cat(False, 4.3))
animals.add(Dog(True, 8))
animals.add(Dog(False, 21))
animals.add(Dog(False, 25))
genderCounter = GenderCounter()
animals.action(genderCounter)
genderCounter.getInfo()
print()
weightCounter = WeightCounter()
animals.action(weightCounter)
weightCounter.getInfo()
print()
输出结果:
1只雄猫,1只雌猫,1只雄狗,2只雌狗。
猫的平均体重是:4.70kg, 狗的平均体重是:18.00kg
访问模式将“数据”和“操作算法”分离,降低了耦合度。将相关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰;操作算法更易拓展。访问模式特别适合应用于以下场景:对象结构中包含的对象类型比较少,而且这些类需要比较固定,很少改变,但经常需要在此对象结构上定义新的操作。
想获得更多更有趣的设计模式吗?一起来阅读以下系列文章吧!
https://github.com/luoweifu/PyDesignPattern
生活中的设计模式——启程之前,请不要错过我【试读】
生活中的监听模式——一坑爹的热水器
生活中的适配模式——身高不够鞋来凑
生活中的状态模式——人有少、壮、老, 水之冰、液、汽
生活中的单例模式——你是我生命的唯一
生活中的职责模式——我的假条去哪了
生活中的中介模式——找房子问中介
生活中的代理模式——帮我拿一下快递
生活中的装饰模式——你想怎么穿就怎么穿
生活中的工厂模式——你要拿铁还是摩卡
生活中的迭代模式——下一个就是你了
生活中的组合模式——自己电脑组装,价格再降三折
生活中的构建模式——你想要一辆车还是一座房
生活中的克隆模式——给你一个分身术
生活中的策略模式——怎么来不重要,人到就行
生活中的命令模式——大闸蟹,走起!
生活中的备忘模式——好记性不如烂笔头
生活中的享元模式——颜料很贵必须充分利用
生活中的外观模式——学妹别慌,学长帮你
生活中的访问模式——一千个读者一千个哈姆雷特
生活中的设计模式——与经典23种设计模式的不解渊源
生活中的设计模式——那些未完待续的设计模式
深入解读过滤器模式——制作一杯鲜纯细腻的豆浆
深入解读对象池技术——共享让生活更便捷
深入解读回调机制——把你技能亮出来
谈谈我对设计模式的理解
谈谈我对设计原则的思考
谈谈我对项目重构的看法