聊聊那些专为算法设计的模式——访问模式
Posted luoweifu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊聊那些专为算法设计的模式——访问模式相关的知识,希望对你有一定的参考价值。
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
引导篇
基础篇
进阶篇
经验篇
以上是关于聊聊那些专为算法设计的模式——访问模式的主要内容,如果未能解决你的问题,请参考以下文章