面向机器学习工程师的Python设计模式:Builder

面向机器学习工程师的Python设计模式:Builder

人工智能开发人员的一项基本技能是编写干净、可重复使用的代码。因此,今天我将使用Deepnote在Python中介绍另一种设计模式。如果你想了解更多关于机器学习的相关内容,可以阅读以下这些文章:
金融中的机器学习:利用随机森林掌握时间序列分类
每个机器学习工程师都应该知道的线性代数!!
2023年面向开发者的十大机器学习(ML)工具
CPU与GPU:哪个更适合机器学习,为什么?

无论你在深度学习主题、统计数据或其他方面有多么优秀,如果你的代码不干净、不容易重用,你将永远无法开发出具有重大影响的东西。这就是为什么我认为数据科学家拥有软件工程技能是非常重要的。设计模式是所有写代码的人都应该知道的东西。今天我们将讨论一个叫做Builder的设计模式。

设计模式只是针对反复出现的问题的通用设计解决方案。与其一遍又一遍地解决同样的问题,不如想想每次遇到同样的问题都可以使用的解决方案,而这些解决方案已经被找到了!幸运的是,有人已经想到让我们的工作更轻松的办法!

设计模式有多种不同。但主要有以下三种:

  • 创造:它是关于创建对象的过程。
  • 结构:它是关于类和对象的组合。
  • 行为:定义类和对象之间如何交互和职责分配。
设计模式(图片由作者提供)

Builder是名为creational的设计模式类的一部分,因为它精确地简化了代码中对象的创建。想象一下,你有一个类,它需要大量的参数来实例化,或者对于python来说,一个类的__init__()方法需要大量的输入参数。

想象一下,你有一门设计公园的课程,也许是因为你正在为一款电子游戏创造环境。你可以通过各种方式自定义公园,添加和删除各种东西。你可以添加游戏,儿童,或者创建一个充满动物的公园等等。

图片由作者提供

但在实施层面,我们如何实施所有这些类型的公园?最直观的解决方案可能是创建一个Park基类,然后其他类将对其进行扩展以包含各种功能。但在这种情况下,我们最终得到四个子类,而在实际项目中,我们将有大量的子类,这将使我们的代码不切实际。

或者我们可以只创建一个类,即类Park,并使用一个巨大的构造函数,可以为其提供大量参数作为输入。但问题是,在大多数情况下,输入参数都是空的,因为我们不希望创建一个拥有一切的公园,而且代码看起来也有点难看。

Builder采用的解决方案是创建所有我们想要包含在Park类的不同方法中的各种功能,称为Builder,而不是将所有东西都放在构造函数中。这样,我们就可以根据需要一步一步地构建公园的各个部分。

ParkBuilder图片由作者提供

让我们开始编码吧!

现在让我们看看如何在Python中实现这种设计模式。在这个例子中,我们想要构建具有不同配置的不同类型的robot。以下代码将由5个基本部分组成。

1. Robot类:

  • 首先,我们创建一个Robot类来表示我们想要构建的对象及其所有属性,例如head、arms、legs、torso和battery。
# Define the Robot class
class Robot:
def __init__(self):
self.head = None
self.arms = None
self.legs = None
self.torso = None
self.battery = None

2.Builder接口:

  • RobotBuilder接口是一个抽象类,它定义了一组用于构建robot对象的不同部分的方法。这些方法包括reset、build_head、build_arms、build_legs、build_torso、build_battery和get_robo。
from abc import ABC, abstractmethod

class RobotBuilder(ABC):
    @abstractmethod
    def reset(self):
        pass

    @abstractmethod
    def build_head(self):
        pass

    @abstractmethod
    def build_arms(self):
        pass

    @abstractmethod
    def build_legs(self):
        pass

    @abstractmethod
    def build_torso(self):
        pass

    @abstractmethod
    def build_battery(self):
        pass

    @abstractmethod
    def get_robot(self):
        pass

3.Concrete Builders:

  • 现在我们有了实现抽象类robotbuilder的Builder类,它们分别是HumanoidRobotBuilder和DroneRobotBuilder。这些Builder赋予robot不同的设置,使它们彼此区别开来。
  • 请记住,每个Builder都维护其正在构建的一个Robot实例。
# Define a Concrete Builder for a Robot
class HumanoidRobotBuilder(RobotBuilder):
    def __init__(self):
        self.robot = Robot()
        self.reset()

    def reset(self):
        self.robot = Robot()

    def build_head(self):
        self.robot.head = "Humanoid Head"

    def build_arms(self):
        self.robot.arms = "Humanoid Arms"

    def build_legs(self):
        self.robot.legs = "Humanoid Legs"

    def build_torso(self):
        self.robot.torso = "Humanoid Torso"

    def build_battery(self):
        self.robot.battery = "Humanoid Battery"

    def get_robot(self):
        return self.robot

# Define a Concrete Builder for a Robot
class DroneRobotBuilder(RobotBuilder):
    def __init__(self):
        self.robot = Robot()
        self.reset()

    def reset(self):
        self.robot = Robot()

    def build_head(self):
        self.robot.head = "Drone Head"

    def build_arms(self):
        self.robot.arms = "No Arms"

    def build_legs(self):
        self.robot.legs = "No Legs"

    def build_torso(self):
        self.robot.torso = "Drone Torso"

    def build_battery(self):
        self.robot.battery = "Drone Battery"

    def get_robot(self):
        return self.robot

4.RobotDirector:

  • RobotDirector类的任务是使用它提供的特定Builder来指导robot的构建。
  • 在这个类中,你将找到set_builder方法来激活你需要的Builder,并使用build_humanoid_robot和build_drone_robot方法来创建不同类型的robot
  • RobotDirector的成员方法最终返回构造好的robot对象。
# Define the RobotDirector class with methods to create different robots
class RobotDirector:
    def __init__(self):
        self.builder = None

    def set_builder(self, builder):
        self.builder = builder

    def build_humanoid_robot(self):
        self.builder.reset()
        self.builder.build_head()
        self.builder.build_arms()
        self.builder.build_legs()
        self.builder.build_torso()
        self.builder.build_battery()
        return self.builder.get_robot()

    def build_drone_robot(self):
        self.builder.reset()
        self.builder.build_head()
        self.builder.build_torso()
        self.builder.build_battery()
        return self.builder.get_robot()

5. 客户端代码:

  • 让我们构建一个RobotDirector实例。
  • 然后构建HumanoidRobotBuilder并将其设置为仿真robot的active Builder。
  • 我们还使用RobotDirector的build_humanoid_robot方法来创建一个仿真robot。
  • 现在我们可以创建一个DroneRobotBuilder,并将其设置为无人机robot的active Builder。
  • 现在我们要使用RobotDirector的build_drone_robot方法来创建一个无人机robot。
  • 最后,我们打印出两种robot的组件。
# Client code
if __name__ == "__main__":
    director = RobotDirector()

    humanoid_builder = HumanoidRobotBuilder()
    director.set_builder(humanoid_builder)
    humanoid_robot = director.build_humanoid_robot()

    drone_builder = DroneRobotBuilder()
    director.set_builder(drone_builder)
    drone_robot = director.build_drone_robot()

    print("Humanoid Robot Components:")
    print(f"Head: {humanoid_robot.head}")
    print(f"Arms: {humanoid_robot.arms}")
    print(f"Legs: {humanoid_robot.legs}")
    print(f"Torso: {humanoid_robot.torso}")
    print(f"Battery: {humanoid_robot.battery}")

    print("\nDrone Robot Components:")
    print(f"Head: {drone_robot.head}")
    print(f"Arms: {drone_robot.arms}")
    print(f"Legs: {drone_robot.legs}")
    print(f"Torso: {drone_robot.torso}")
    print(f"Battery: {drone_robot.battery}")

Builder模式将一个复杂对象的构建与表示分离。正如我们在这个例子中看到的,RobotDirector负责编排构建过程,但不知道创建不同类型robot的具体步骤。在本例中,我们称之为HumanoidRobotBuilder和DroneRobotBuilder的Builder为构建特定的robot配置提供逐步的实现。

该模式具有灵活性和可扩展性,支持创建具有可变属性的复杂对象,同时保持客户端代码的整洁性和易用性。所有这些都使我们能够以一种清晰一致的方式构建复杂的对象。

感谢阅读!你还可以订阅我们的YouTube频道,观看大量大数据行业相关公开课:https://www.youtube.com/channel/UCa8NLpvi70mHVsW4J_x9OeQ;在LinkedIn上关注我们,扩展你的人际网络!https://www.linkedin.com/company/dataapplab/

原文作者:Marcello Politi
翻译作者:文杰
美工编辑:过儿
校对审稿:Chuang
原文链接:https://towardsdatascience.com/design-patterns-with-python-for-machine-learning-engineers-builder-45b8e749f134