2025--简单点--python之状态模式

一个context有可以切换多个state,切换到不同的state可以做不同的handle。
该模式将与状态相关的行为抽取到独立的状态类中, 让原对象将工作委派给这些类的实例, 而不是自行进行处理。

from __future__ import annotations
from abc import ABC, abstractmethod


class Context:
    """
    The Context defines the interface of interest to clients. It also maintains
    a reference to an instance of a State subclass, which represents the current
    state of the Context.
    """

    _state = None
    """
    A reference to the current state of the Context.
    """

    def __init__(self, state: State) -> None:
        self.transition_to(state)

    def transition_to(self, state: State):
        """
        The Context allows changing the State object at runtime.
        """

        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    """
    The Context delegates part of its behavior to the current State object.
    """

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()


class State(ABC):
    """
    The base State class declares methods that all Concrete State should
    implement and also provides a backreference to the Context object,
    associated with the State. This backreference can be used by States to
    transition the Context to another State.
    """

    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context) -> None:
        self._context = context

    @abstractmethod
    def handle1(self) -> None:
        pass

    @abstractmethod
    def handle2(self) -> None:
        pass


"""
Concrete States implement various behaviors, associated with a state of the
Context.
"""


class ConcreteStateA(State):
    def handle1(self) -> None:
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")
        self.context.transition_to(ConcreteStateB())

    def handle2(self) -> None:
        print("ConcreteStateA handles request2.")


class ConcreteStateB(State):
    def handle1(self) -> None:
        print("ConcreteStateB handles request1.")

    def handle2(self) -> None:
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")
        self.context.transition_to(ConcreteStateA())


if __name__ == "__main__":
    # The client code.

    context = Context(ConcreteStateA())
    context.request1()
    context.request2()

output:
Context: Transition to ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA

状态模式的优点

避免了过多的条件判断:状态模式通过将每个状态的行为封装到对应的类中,避免了在上下文中使用大量的条件判断语句(如if-else或switch-case)来根据状态执行不同的行为。

符合开闭原则:当需要增加新的状态时,只需要添加新的状态类,而不需要修改上下文类或其他状态类。
使状态转换更加明确:每个状态类只关心自己状态下的行为以及如何转换到其他状态,使得状态转换的逻辑更加清晰。

状态模式的缺点

  1. 增加了类的数量:每个状态都需要一个对应的类,可能会导致系统中类的数量增加。
  2. 状态转换逻辑分散:状态转换的逻辑分散在各个具体状态类中,可能会使得状态转换的整体逻辑不够直观。

适用场景

一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。
一个操作中含有大量的条件语句,且这些条件依赖于对象的状态。

通过状态模式,我们可以将复杂的条件判断转换为状态类之间的转换,使得代码更加清晰和可维护。

<think>好的,用户的问题是如何用简单的代码通过`move_base_msgs/MoveBaseActionResult`实现到达目标位置后发送文本。我需要先理解用户的需求和使用场景。 首先,用户提到了ROS中的`move_base`节和`move_base_msgs/MoveBaseActionResult`消息类型。这表明他们正在使用ROS进行机器人导航,并希望在机器人到达目标位置后触发某个动作,比如发送文本信息。用户可能是在开发一个自动导航的机器人,需要在任务完成后进行通知或其他交互。 接下来,我需要考虑如何监听`move_base`的结果。在ROS中,动作服务器通常会发布结果到特定的主题,比如`move_base/result`。用户需要使用这个主题来订阅结果消息。`MoveBaseActionResult`消息的结构中,`status`字段会指示动作的最终状态,例如成功、失败等。用户需要检查状态是否为成功(`status.status == 3`),然后触发发送文本的操作。 然后,如何发送文本呢?可能的方式有很多,比如在终端打印、发布到某个ROS主题,或者调用其他服务。用户没有具体说明发送文本的方式,所以可能需要提供一个通用的方法,比如使用`rospy.loginfo`打印日志,或者发布到一个自定义的主题。考虑到用户希望代码简单,使用日志输出可能是最直接的方式。 接下来是代码结构。用户需要一个订阅者来监听`move_base/result`主题,并在回调函数中处理结果。代码应该包括ROS节的初始化、订阅者的创建,以及回调函数的实现。在回调函数中,判断状态是否为成功,然后执行发送文本的操作。 可能需要注意的问题包括:确保主题名称正确,消息类型的正确导入,以及状态的正确判断。另外,用户可能需要处理多个结果消息的情况,比如在连续导航任务中,每次到达目标都会触发一次回调。 此外,用户可能希望了解如何扩展此功能,比如添加超时处理、错误处理,或者与其他节通信。但根据当前问题,只需提供最简化的实现即可。 最后,验证代码的正确性。确保导入正确的消息类型,主题名称与ROS环境中的一致,并且状态判断正确。测试时,可以发送一个目标位置,观察当机器人到达时是否触发了文本发送。 总结步骤: 1. 导入必要的ROS库和消息类型。 2. 创建订阅者监听`move_base/result`主题。 3. 在回调函数中检查状态是否为成功。 4. 成功时执行发送文本的操作(如打印日志)。 5. 保持节运行以持续监听。 现在需要将这些步骤转化为简洁的Python代码,并确保符合ROS的编程规范。</think>要实现通过`move_base_msgs/MoveBaseActionResult`在到达目标位置后发送文本,可采用ROS订阅者模式监听导航结果。以下是简化实现步骤: ```python #!/usr/bin/env python import rospy from move_base_msgs.msg import MoveBaseActionResult from std_msgs.msg import String def result_callback(msg): # 当状态为3时表示成功到达(SUCCEEDED) if msg.status.status == 3: rospy.loginfo("到达目标位置,正在发送通知文本...") # 创建文本发布者(需提前rostopic pub /notification) pub.publish("NAVIGATION_COMPLETED") if __name__ == '__main__': rospy.init_node('nav_result_monitor') # 创建结果订阅(注意实际topic名称可能含命名空间) rospy.Subscriber('/move_base/result', MoveBaseActionResult, result_callback) # 创建文本发布者(假设使用/notification主题) pub = rospy.Publisher('/notification', String, queue_size=10) rospy.spin() ``` 代码说明: 1. 订阅`/move_base/result`主题监听导航结果[^1] 2. 通过`status.status`判断是否成功到达(值3对应`actionlib_msgs/GoalStatus SUCCEEDED`) 3. 使用独立发布者发送文本消息到`/notification`主题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

万物琴弦光锥之外

给个0.1,恭喜老板发财

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

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

打赏作者

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

抵扣说明:

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

余额充值