我正在编写一个用于模拟分布式传感器群的 python 平台。这个想法是最终用户可以编写一个由 SensorNode 行为(通信、日志记录等)组成的自定义节点,并实现许多不同的传感器。
下面的例子简要地演示了这个概念。
#prewritten
class Sensor(object):
def __init__(self):
print "Hello from Sensor"
#...
#prewritten
class PositionSensor(Sensor):
def __init__(self):
print "Hello from Position"
Sensor.__init__(self)
#...
#prewritten
class BearingSensor(Sensor):
def __init__(self):
print "Hello from Bearing"
Sensor.__init__(self)
#...
#prewritten
class SensorNode(object):
def __init__(self):
print "Hello from SensorNode"
#...
#USER WRITTEN
class MySensorNode(SensorNode,BearingSensor,PositionSensor):
def CustomMethod(self):
LogData={'Position':position(), 'Bearing':bearing()} #position() from PositionSensor, bearing() from BearingSensor
Log(LogData) #Log() from SensorNode
新编辑:
首先概述我想要实现的目标:我正在编写一个模拟器来模拟群体智能算法,特别关注移动传感器网络。这些网络由许多小型机器人组成,它们相互交流各个传感器数据,以构建复杂的环境感官地图。
该项目的基本目标是开发一个模拟平台,为传感器提供抽象接口,以便可以将相同的用户实现功能直接移植到运行嵌入式 linux 的机器人群中。由于机器人实现是目标,因此我需要设计成软件节点的行为相同,并且只能访问物理节点所拥有的信息。
作为模拟引擎的一部分,我将提供一组模拟不同类型传感器和不同类型传感器节点的类。我希望从用户那里抽象出所有这些复杂性,以便用户所要做的就是定义节点上存在哪些传感器,以及正在实施哪种类型的传感器节点(移动、固定位置)。
我最初的想法是每个传感器都会提供一个 read() 方法,该方法将返回相关值,但是在阅读了对问题的回答后,我发现可能更具描述性的方法名称会是有益的(.distance(), .position( )、.bearing() 等)。
我最初想为传感器使用单独的类(具有共同的祖先),以便技术更高的用户可以轻松地扩展现有类之一以创建新的传感器,如果他们愿意的话。例如:
Sensor
|
DistanceSensor(designed for 360 degree scan range)
| | |
IR Sensor Ultrasonic SickLaser
(narrow) (wider) (very wide)
我最初考虑多重继承的原因(尽管它半破坏了继承的 IS-A 关系)是由于模拟系统背后的基本原理。让我解释:
用户实现的 MySensorNode 不应直接访问其在环境中的位置(类似于机器人,通过传感器接口间接访问),同样,传感器不应知道它们在哪里。然而,这种缺乏直接知识带来了一个问题,因为传感器的返回值都取决于它们在环境中的位置和方向(需要对其进行模拟才能返回正确的值)。
SensorNode,作为模拟库中实现的一个类,负责在 pygame 环境中绘制 MySensorNode - 因此,它是唯一应该直接访问环境中传感器节点的位置和方向的类。
SensorNode 还负责环境中的平移和旋转,但是这种平移和旋转是电机驱动的副作用。
我的意思是机器人不能直接改变它们在世界中的位置,它们所能做的就是为电机提供动力,而在世界中的运动是电机与环境相互作用的副作用。我需要在模拟中准确地建模。
因此,要移动,用户实现的功能可以使用:
motors(50,50)
作为副作用,此调用将改变节点在世界中的位置。
如果 SensorNode 是使用组合实现的,SensorNode.motors(...) 将无法直接更改实例变量(例如位置),MySensorNode.draw() 也不会解析为 SensorNode.draw(),因此 SensorNode imo 应该使用继承来实现。
在传感器方面,像这样的问题组合的好处是显而易见的,MySensorNode 是由许多传感器组成的——说得够多了。
然而,我看到的问题是传感器需要访问它们在世界中的位置和方向,如果你使用组合,你最终会得到如下调用:
>>> PosSensor.position((123,456))
(123,456)
再说一遍 - 想一想,你可以在初始化时将 self 传递给传感器,例如:
PosSensor = PositionSensor(self)
然后稍后
PosSensor.position()
但是这个 PosSensor.position() 需要访问实例的本地信息(在init () 期间作为 self 传递),那么当您可以在本地访问信息时为什么还要调用 PosSensor 呢?同样将您的实例传递给您所组成的对象似乎不太正确,跨越了封装和信息隐藏的界限(即使python在支持信息隐藏的想法方面做得不多)。
如果解决方案是使用多重继承来实现的,这些问题就会消失:
class MySensorNode(SensorNode,PositionSensor,BearingSensor):
def Think():
while bearing()>0:
# bearing() is provided by BearingSensor and in the simulator
# will simply access local variables provided by SensorNode
# to return the bearing. In robotic implementation, the
# bearing() method will instead access C routines to read
# the actual bearing from a compass sensor
motors(100,-100)
# spin on the spot, will as a side-effect alter the return
# value of bearing()
(Ox,Oy)=position() #provided by PositionSensor
while True:
(Cx,Cy)=position()
if Cx>=Ox+100:
break
else:
motors(100,100)
#full speed ahead!will alter the return value of position()
希望这次编辑澄清了一些事情,如果您有任何问题,我很乐意尝试澄清它们
旧事:
构造 MySensorNode 类型的对象时,需要调用超类中的所有构造函数。我不想让用户不得不为 MySensorNode 编写一个自定义构造函数,该构造函数从每个超类调用构造函数。理想情况下,我希望发生的是:
mSN = MySensorNode()
# at this point, the __init__() method is searched for
# and SensorNode.__init__() is called given the order
# of inheritance in MySensorNode.__mro__
# Somehow, I would also like to call all the other constructors
# that were not executed (ie BearingSensor and PositionSensor)
任何见解或一般性评论将不胜感激,干杯:)
旧编辑:做类似的事情:
#prewritten
class SensorNode(object):
def __init__(self):
print "Hello from SensorNode"
for clss in type(self).__mro__:
if clss!=SensorNode and clss!=type(self):
clss.__init__(self)
这很有效,因为 self 是 MySensorNode 的一个实例。然而,这个解决方案很混乱。