我一直在努力学习OOP在过去的几周时间里,尽我所能,我也学到了很多,但我不能确定这一个,我应该我的类层次结构是什么样子?
想象一下,两个班,这里有一个Level
-class:
class Level(object):
def __init__(self, level, exp):
self.level = level
self.exp = exp
@property
def required_exp(self, level=None):
return 80 + 40 * (level or self.level)
def add_exp(self, exp):
self.exp += exp
while self.exp >= self.required_exp:
self.exp -= self.required_exp
self.level += 1
显然,它也有一些其他的方法也一样,但是这是基本的想法。
现在第二类被称为Player
。 它有一些属性,如: name
, health
, level
, experience points
, damage
等。
我已经学会了到目前为止(有人这么说这)就是问自己一个问题,当我不知道是否使用继承( is-a
-relationship)或属性( has-a
-relationship)。 现在的问题是: 是Player中的级别,还是球员有水平?
嗯......这是两者都不是。 球员肯定不是一个级别的,我敢肯定的。 和球员有它的水平,但水平不等于Level
一流。 相反,播放器有水平和经验值,这是两个属性Level
类。 您还可以添加点经验给玩家,所以它才有意义要继承它Level
。
一点题外话,在namings真的不作出任何意义,我满意。 这将是有意义的有这样的: Level.increase(self)
由一个增加一个级别。 然而,对于玩家会更有意义调用Player.level_up(self)
,因为在大多数(全部?)RPG游戏使用。 调用Player.increase(self)
并没有真正使任何意义,你不能增加Player
的一个,你增加它的水平的一个。 话又说回来,调用Level.level_up(self)
并没有做出太大的意义要么...
所以,我认为我应该使用Level
,如果它是一个接口,继承Player
从它(和其他子类),但我不能肯定,所以我决定要问你,因为我在这里学习反正。 我该怎么办? 什么是用最恰当的方式Level
与Player
?
I believe I'm the one who told you to ask yourself the question: "Is class A a class B, or does class A have a class B?", so I feel like I have to answer this question.
I'm not 100% sure of what your level actually does, but I'm assuming it's one similar to the one used in Pokemon, World of Warcraft, League of Legends, and thousands of other games.
If so, you've already gone wrong with your Level
-class, it shouldn't be like that.
You're right on one thing for sure;
"Player certainly is not a level"
As others have already mentioned, you should just go with has-a relationship.
Player does have level, we both know that.
However, you're telling me player doesn't have an attribute of type Level
, but rather an integer level
-attribute to hold the numeric value of your Level
-class.
This should already ring some bells, but here's a tip: It's the same as having a Name
-class that has a string
-type attribute called name
inside it.
So the answer is:
Name
class should already be a string itself, it should inherit from string
, instead of having a string
attribute inside it to hold its value.
The same applies for your Level
, it's already an integer itself so inherit it from int
, then add exp
and its methods.
Now you can use player.level
to return the integer value of player's level.
And to get the exp
, you "have to" use player.level.exp
.
I quoted the "have to", since even though it might sound weird, exp
IS an attribute of level's.
It's basically the same as a decimal point for a number, makes sense?
Also, calling something like player.level.increase()
makes much more sense now.
Although, it's already an integer value, why not just do player.level += 1
?
And if you need some advanced stuff inside the addition, you could just override the Level.__add__(self, value)
method.
I can't think of a single reason why wouldn't you need this though? (not now that you've already made required_exp
a property)
玩家拥有A级。 正如你所说的,“球员肯定不是一个级别的。” 当您使用继承,这意味着球员的水平(这当然没有什么意义的话)的一个亚型。
这是一个明确的具有-的关系。 用的方法,如电平相互作用player1.levelup()
或player1.addxp()
其指的是级别属性。
如果您已经确定播放器是不是一个级别的,那么继承不是正确的机制。 继承适用于像“汽车是车辆和摩托车是借车”的关系,所以在这种情况下这两个汽车和摩托车是车辆的子类。
然而,这种关系并没有任何一个真正适合组成 ,在该级别不应该表示为与它自己的功能另一个阶级的意识。 这是事实,一个球员的水平,但正如你指出, player.level_up()
和player.add_experience()
比调用这些方法与更清晰的level
对象。 这是因为随着玩家等级的交互是通过它的方法是有道理的,不是player.level.level
。 那么你应该考虑移动你的等级类的功能播放器:
球员肯定不是一个级别的,但他有一个水平。 我不明白你的问题用在播放器类上面定义的一级类,因为它跟踪的所有因为这是一个水平的一部分玩家的重要信息。
相反,跟踪这两个水平和相对于该级别的额外经验的,你可以简单地跟踪的整体体验 。
从总的经验,你可以得到的水平和经验的数量需要达到一个新的水平,或任何其他这样的量,你可能会感兴趣。
例如,
class Player(object):
def __init__(self, exp=0):
self.exp = exp
@property
def level(self):
if self.exp<80:
return 0
return (self.exp-80)//40 + 1
@property
def required_exp(self):
return 80 + 40*self.level
def add_exp(self, exp):
self.exp += exp
ringo = Player(exp=80)
print(ringo.level)
# 1
print(ringo.required_exp)
# 120