聊聊那些专为算法设计的模式——访问模式

AI越来越火热,人工智能已然成风!而人工智能最重要是各种算法,因此机器学习越来越受到追捧,算法越来越被重视。

作为一个算法的研究者,写出一手高级算法当然是令人兴奋的一件事!但你是否有时会有这种感觉:

  1. 写的算法很难通用于所有的数据类型!每来一个新类型的数据,又得改一下算法,或新加一个方法来支持这种类型。
  2. 有时候多个算法需要灵活组合,甚至每个算法的顺序不一样都会产生不一样的效果;每一种组合都要为其构建一个新算法,即累又麻烦。
  3. 算法越来越多,自建的算法库也越来越庞大而难于管理;

这个时候,让你的算法具有更好通用性、拓展性就显得极为重要!因此,你必须要掌握几个重要的设计模式来优化你的代码,解决这些问题。今天就来聊聊那些专为算法设计的模式:策略模式、模板方法模式、访问模式。

访问模式

封装一些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

访问模式的核心思想在于:可以在不改变数据结构的前提下定义作用于这些元素的新操作。将数据结构和具体算法进行解耦,而且能更方便地拓展新的操作。

访问模式的代码框架

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个操作:

  1. 在这些宠物中雌猫、雄猫、雌狗、雄狗的数量分别是多少。
  2. 猫的平均体重和狗的平均体重分别是多少。

这个时候,如果要在猫和狗的对象上添加这些操作,将会增加非常多的方法而污染原有的对象;而且这些操作的拓展性也将非常差。这时访问模式是解决这个问题的最好方法,我们一起看一下具体的实现如下:

源码示例:

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种设计模式的不解渊源

生活中的设计模式——那些未完待续的设计模式

进阶篇

深入解读过滤器模式——制作一杯鲜纯细腻的豆浆

深入解读对象池技术——共享让生活更便捷

深入解读回调机制——把你技能亮出来

经验篇

谈谈我对设计模式的理解

谈谈我对设计原则的思考

谈谈我对项目重构的看法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌尘(MoChen)

爱打赏的人技术成长更开哦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值