困惑的OO设计问题 [英] Puzzling OO design problem

查看:49
本文介绍了困惑的OO设计问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个我遇到的问题的设计,这就像

这个(不,这不是功课):


1.域类的(单继承)层次结构,比如

A< -B< - ..< -Z(箭头指向继承树中的父项)。

2.这个层次结构随着时间的推移逐渐演变为每个

类的不同版本。例如,版本'1的层次结构将是A_v1< -B_v1

< - ..< -Z_v1。

3.在运行时,只有一个版本由工厂函数选择。


到目前为止,继承图将如下:


A< - A_V1 ...< - A_Vn

^ ^ ^

| | |

B< - B_V1 ...< - B_Vn

.. 。

.. 。

.. 。

^ ^ ^

| | |

Z< - Z_V1 ...< - Z_Vn

这可以通过多重继承来实现(例如

B_V1(B ,A_V1))或使用桥设计模式| Z |时间,每行一个
。两种解决方案都可以接受;由多重继承引起的没有歧义

(或者它们被正确解析

,无论何时发生)。


现在问题是这个继承点阵中有漏洞:

并非所有版本都引入了所有类型的新变体;例如

B_V5可能会丢失,这意味着最新版本的

B将用于版本5(比如B_V2)。我的第一个想法是动态地创建所有缺失类的

,但它有点模糊,而且它可能不那么简单。有没有更优雅的解决方案,无论是一般设计模式还是一些聪明的python元编程黑客?


乔治

I''m looking for a design to a problem I came across, which goes like
this (no, it''s not homework):

1. There is a (single inheritance) hierarchy of domain classes, say
A<-B<-..<-Z (arrows point to the parent in the inheritance tree).
2. This hierarchy evolved over time to different versions for each
class. So for example, version''s 1 hierarchy would be A_v1 <-B_v1
<-..<-Z_v1.
3. At runtime, only one version is selected by a factory function.

Up to this point, the inheritance graph would be the following:

A <- A_V1 ... <- A_Vn
^ ^ ^
| | |
B <- B_V1 ... <- B_Vn
.. . .
.. . .
.. . .
^ ^ ^
| | |
Z <- Z_V1 ... <- Z_Vn
This could be implemented either with multiple inheritance (e.g.
B_V1(B,A_V1)) or using the bridge design pattern |Z| times, one per
each row. Both solutions would be acceptable; there are no ambiguities
caused by the multiple inheritance (or they are resolved properly
whenever they occur).

Now the problem is that there are ''holes'' in this inheritance lattice:
Not all versions introduced new variations of all types; for instance
B_V5 could be missing, meaning that the most recent earlier version of
B would be used in version 5 (say B_V2). My first thought was to create
all the missing classes dynamically, but it''s somewhat obscure and it
may not be that simple. Is there a more elegant solution, either a
general design pattern or some clever python metaprogramming hack ?

George

推荐答案

2005年4月8日星期五04:42:52 PM -0700,George Sakkis写道:
On Fri, Apr 08, 2005 at 04:42:52PM -0700, George Sakkis wrote:
我正在寻找一个设计我遇到的一个问题,就像
这个(不,这不是作业):

1.域类的(单继承)层次结构,比如说
A< -B< - ..< -Z(箭头指向继承树中的父级)。
2.此层次结构随着时间的推移逐渐演变为每个类的不同版本。例如,版本'1的层次结构将是A_v1< -B_v1
< - ..< -Z_v1。
3.在运行时,工厂函数只选择一个版本。

到目前为止,继承图如下:

A< - A_V1 ...< - A_Vn
^ ^ ^
| | | B< - B_V1 ......< - B_Vn
。 。 。
。 。 。
。 。 。
^ ^ ^
| | |
Z< - Z_V1 ...< - Z_Vn

这可以通过多重继承(例如
B_V1(B,A_V1))或使用桥来实现设计模式| Z |时间,每行一个。两种解决方案都可以接受;由于多重继承而导致没有歧义(或者无论什么时候它们都能正确解决)。

现在的问题是这里有'漏洞'继承格:
并非所有版本都引入了所有类型的新变种;例如,B_V5可能会丢失,这意味着最新的早期版本的
B将用于版本5(比如说B_V2)。我的第一个想法是动态地创建所有缺失的类,但它有点模糊,它可能不那么简单。有没有一个更优雅的解决方案,无论是一般设计模式还是一些聪明的python元编程黑客?
I''m looking for a design to a problem I came across, which goes like
this (no, it''s not homework):

1. There is a (single inheritance) hierarchy of domain classes, say
A<-B<-..<-Z (arrows point to the parent in the inheritance tree).
2. This hierarchy evolved over time to different versions for each
class. So for example, version''s 1 hierarchy would be A_v1 <-B_v1
<-..<-Z_v1.
3. At runtime, only one version is selected by a factory function.

Up to this point, the inheritance graph would be the following:

A <- A_V1 ... <- A_Vn
^ ^ ^
| | |
B <- B_V1 ... <- B_Vn
. . .
. . .
. . .
^ ^ ^
| | |
Z <- Z_V1 ... <- Z_Vn
This could be implemented either with multiple inheritance (e.g.
B_V1(B,A_V1)) or using the bridge design pattern |Z| times, one per
each row. Both solutions would be acceptable; there are no ambiguities
caused by the multiple inheritance (or they are resolved properly
whenever they occur).

Now the problem is that there are ''holes'' in this inheritance lattice:
Not all versions introduced new variations of all types; for instance
B_V5 could be missing, meaning that the most recent earlier version of
B would be used in version 5 (say B_V2). My first thought was to create
all the missing classes dynamically, but it''s somewhat obscure and it
may not be that simple. Is there a more elegant solution, either a
general design pattern or some clever python metaprogramming hack ?




错误,您可能想解释一下这些事情是做什么的而不是

抽象描述你是如何做到的。看起来你是以正常的方式使用继承来使用

_and_你用它来处理

某种类型的版本(可能是稳定的界面版本?我不知道)。


让我们知道哪些部分需要继承,以及你有什么

只是为了方便使用了继承的副作用

(版本化,我认为)。


一个更具体的例子会更容易评论,如果可能的话

做一个简单的例子(也许只有两个班,每个版本有两个版本。


-jackdied



Err, you might want to explain what these things do instead of an
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don''t know).

Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied


>呃,你可能想解释一下这些事情是做什么而不是
> Err, you might want to explain what these things do instead of an
抽象描述你是怎么做的。看起来你正在以正常方式使用继承_and_你正在使用它来处理某种类型的版本控制(可能是稳定的界面版本?我不知道b $ b知道)。让我们知道哪些部分需要继承,以及你为了方便而使用继承的副作用
(版本化,我认为)。

一个更具体的例子会更容易评论,如果可能的话做一个简单的例子(也许只是两个版本,每个版本有两个版本)。

-jackdied
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don''t know).
Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied




我故意抽象问题去除无关的

细节,但这里有一个更具体(但仍然简化)的例子。

我希望现在更清楚了。


乔治


#================= ============


def worldModelFactory(版本):

如果版本< 2:返回WorldModel()

else:返回WorldModel_v2()


类WorldModel(对象):


def __init __(self):

self.ourGoal = self.FieldObject(x = -50,y = 0)

self.theirGoal = self.FieldObject(x = + 50,y = 0)

self.ball = self.MovableObject()

self.teammates = [self.Player(i)for x in xrange(1,12) )]

self.opponents = [self.Player(i)for i in xrange(1,12)]


class FieldObject(object):

def __init __(self,id = None,x = 0,y = 0):

self.id = id

self._pos = (x,y)

def position(self):

''''''获取或估计当前位置。''''''

返回self._pos


类MovableObject(FieldObject):

def speed(self):

'' ''''获取或估计当前的速度。'''''

#[实施剪断]


类播放器(MovableObject):

def passBall(se如果,力量,队友):

'''''将球传给队友。''''''

#[实施剪辑]

类WorldModel_v2(WorldModel):


类FieldObject(WorldModel.FieldObject):

''''''FieldObject的新实现。 ''''''

def position(self):

#[新实现剪辑]

传递

类MovableObject(WorldModel.MovableObject,FieldObject):

''''''MovableObject自上一版本以来没有变化。

这个课程的唯一原因是使WorldModel_v2.Player可以访问
WorldModel_v2.FieldObject



''''''

通过


类玩家(WorldModel.Player,MovableObject):

''''' '玩家的新实现。'''''

def passBall(自我,权力,队友):

#WorldModel_v2.FieldObject.position()应该被调用

myPosition = self.position()

#[新实现剪辑]


#========= ====================



I intentionally abstracted the problem to remove the irrelevant
details, but here''s a more concrete (though still simplified) example.
I hope it is more clear now.

George

#=============================

def worldModelFactory(version):
if version < 2: return WorldModel()
else: return WorldModel_v2()

class WorldModel(object):

def __init__(self):
self.ourGoal = self.FieldObject(x=-50, y=0)
self.theirGoal = self.FieldObject(x=+50, y=0)
self.ball = self.MovableObject()
self.teammates = [self.Player(i) for i in xrange(1,12)]
self.opponents = [self.Player(i) for i in xrange(1,12)]

class FieldObject(object):
def __init__(self, id=None, x=0, y=0):
self.id = id
self._pos = (x,y)
def position(self):
''''''Get or estimate the current position.''''''
return self._pos

class MovableObject(FieldObject):
def speed(self):
''''''Get or estimate the current speed.''''''
# [implementation snipped]

class Player(MovableObject):
def passBall(self,power,teammate):
''''''Pass the ball to the teammate.''''''
# [implementation snipped]
class WorldModel_v2(WorldModel):

class FieldObject(WorldModel.FieldObject):
''''''New implementation of FieldObject.''''''
def position(self):
# [new implementation snipped]
pass

class MovableObject(WorldModel.MovableObject, FieldObject):
''''''MovableObject didn''t change since the previous version. The
only reason for this class is to make
WorldModel_v2.FieldObject
accessible to WorldModel_v2.Player.
''''''
pass

class Player(WorldModel.Player, MovableObject):
''''''New implementation of Player.''''''
def passBall(self,power,teammate):
# WorldModel_v2.FieldObject.position() should be called
myPosition = self.position()
# [new implementation snipped]

#=============================


2005年4月8日星期五06:40 :54PM -0700,George Sakkis写道:
On Fri, Apr 08, 2005 at 06:40:54PM -0700, George Sakkis wrote:
呃,你可能想解释一下这些事情是做什么而不是描述你是怎么做的抽象描述它。看起来你正在以正常方式使用继承_and_你正在使用它来处理某种类型的版本化(可能是稳定的接口版本?我不知道)。
Err, you might want to explain what these things do instead of an
abstract description of how you are doing it. It looks like you are
using inheritance in the normal way _and_ you are using it to handle
versioning of some kind (maybe stable interface releases? I don''t know).

让我们知道哪些部分需要继承,以及你为了方便而使用继承的副作用
(版本化,我认为)。

一个更具体的例子会更容易评论,如果可能的话做一个简单的例子(也许只是两个版本,每个版本有两个版本)。

-jackdied

Let us know what parts need inheritance for, and what you have
just been using a side effect of inheritance for as a convenience
(versioning, I think).

A more concrete example would be easier to comment on, if possible
do a simple one (maybe just two classes with two versions each).

-jackdied



我有意提取问题以删除不相关的细节,但这里有一个更具体(但仍然简化)的例子。
我希望现在更清楚了。



I intentionally abstracted the problem to remove the irrelevant
details, but here''s a more concrete (though still simplified) example.
I hope it is more clear now.




<简化版本的George'的exmaple>

def worldModelFactory(版本):
如果版本< 2:返回WorldModel()
else:返回WorldModel_v2()
类WorldModel_v1(对象):
类Player(对象):
def foo(self):传递#v1实现foo()
类WorldModel_v2(对象):
类Player(WorldModel_v2.Player):
def foo(self):传递#v2执行foo ()


所以你使用WorldModel_ *类作为命名空间来保存一组可能继承和扩展或重新定义前一个类WorldModel_ *命名空间中的
类。这似乎在您的原始帖子中做了您想要的

,即如果在v1中定义了一个类但在v2中没有定义

v2将只使用v1的实现。默认情况下,WorldModel_v2将从_v1继承

播放器,因此开箱即可正常工作。


所以你应该没事,但我认为你的问题更实际

比适当的OO方式做什么?这在python中有点像sh b b b b b b b b b b b b b。我们喜欢什么是最简单和可读的?所以这里有一些

实用建议(好吧,至少这是我的意图)。


您是否使用* _v1命名约定来实现向后兼容?

向后兼容是一个巨大的痛苦,我注意到你是从.edu地址张贴的b $ b,所以如果这只是你正在工作的东西
你自己或小组中的


代码中删除了版本控制方面。与群组中的其他人交谈更容易。

从您的示例(我过度修剪)看起来您正在使用



<boiled down version of George''s exmaple>
def worldModelFactory(version):
if version < 2: return WorldModel()
else: return WorldModel_v2()

class WorldModel_v1(object):
class Player(object):
def foo(self): pass # v1 implementation of foo()

class WorldModel_v2(object):
class Player(WorldModel_v2.Player):
def foo(self): pass # v2 implementation of foo()
So you are using the WorldModel_* classes as a namespace to hold a
set of classes that might inherit and extend or redefine the previous
classes in a WorldModel_* namespace. This seems to do what you wanted
in your original post, namely if a class is defined in v1 but not in v2
that v2 would just use v1''s implementation. WorldModel_v2 will inherit
Player from _v1 by default, so that should work OK out of the box.

So you should be fine there, but I think your question is more practical
than "what is the proper OO way to do it?" which is a bit of a shibboleth
in python. We like "what is easiest and readable?" So here are some
practical recommendations (well, at least that''s my intention).

Are you using the *_v1 naming convention for backwards compatibility?
Backwards compatibility is a giant pain in the ass, I notice you are
posting from a .edu address so if this is just something you are working
on by yourself or in a small group drop the versioning aspects from the
code. Talking to the other people in the group is easier.
From your example (which I over-pruned) it looks like you are using



WorldModel名称空间定义运行迭代的参数

的游戏。 WorldModel下的类别类似于规则/物理定义(MovableObject),团队的坐标-A

球门柱,球队-B球门柱的坐标,球队-A策略(球员) ),

和B队战略(也是球员)。 WorldModel将成为游戏板。


如果是这样的话,让WorldModel成为一块板子 - 将玩家等放在它下面

作为名称空间,并给它一个运行()接受参数的函数。

将玩家衍生物命名为PlayerDumb,PlayerSmart,PlayerAggressive

等,你可能会有更多的目标或物理规则。

实际的主程序看起来像


ob = WorldModel()#standard 100x100 board

winner = ob .run(physics = MovableObject,#定义摩擦和重力

team_a_goal =(50,25),

team_b_goal =(5,5),

team_a_strategy = PlayerDumb,

team_b_strategy = PlayerAggressive,



打印赢家是,赢家


我写的比我的意思更多,但基本的想法是,当你不需要时,不要使用课程

- 它只是让事情变得更复杂。那个

应该给你更多时间来处理有趣的部分(玩家

策略,我想象)。


-jackdied


the WorldModel namespace to define parameters for running an iteration
of a game. The classes under "WorldModel" are something like
the rules/physics definition (MovableObject), coordinates of the team-A
goalpost, coordinates of the team-B goalpost, team-A strategy (Player),
and team-B strategy (also Player). WorldModel would be the gameboard.

If so, make WorldModel just a board - drop putting Player etc under it
as a namespace, and give it a run() function that takes parameters.
Name the Player derivatives as PlayerDumb, PlayerSmart, PlayerAggressive
etc, you''ll probably have a lot more of those than goals or physics rules.
The actual main routine would look something like

ob = WorldModel() # standard 100x100 board
winner = ob.run(physics=MovableObject, # defines friction and gravity
team_a_goal=(50,25),
team_b_goal=(5,5),
team_a_strategy=PlayerDumb,
team_b_strategy=PlayerAggressive,
)
print "Winner is ", winner

I wrote more than I meant to, but the basic idea is don''t use classes
when you don''t need to - it just makes things more complex. That
should give you more time to tackle the interesting parts (player
strategies, I''d imagine).

-jackdied


这篇关于困惑的OO设计问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆