1

ここ数週間、できる限り OOP を学ぼうとしてきました。多くのことを学びましたが、これについては確信が持てません。私のクラス階層はどのように見えるべきでしょうか?

2 つのクラスを想像してください。ここに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

明らかに、他の方法もいくつかありますが、それが基本的な考え方です。

2 番目のクラスは と呼ばれPlayerます。、、、、、などnameの属性があります。healthlevelexperience pointsdamage

is-a私がこれまでに学んだこと (SO の誰かが言った) は、継承 ( -relationship ) と属性 ( -relationship )のどちらを使用するべきかわからない場合に、自問自答することですhas-a。質問は次のとおりです:プレーヤーはレベルですか、それともプレーヤーにはレベルがありますか?

うーん…どちらでもない。プレーヤーは確かにレベルではありません。LevelPlayer にはレベルがありますが、レベルはクラスと等しくありません。Level代わりに、プレイヤーにはクラスの属性であるレベルと経験値があります。Player に経験値を追加することもできるので、 から継承するのが理にかなっていLevelます。

補足として、ネーミングも私にはまったく意味がありません。次のようなものを用意するのは理にかなっています:Level.increase(self)レベルを 1 つ上げます。ただし、プレイヤーにとってはPlayer.level_up(self)、ほとんどの (すべての?) RPG ゲームで使用されているように、 を呼び出す方が理にかなっています。呼び出しPlayer.increase(self)ても意味がありませんPlayer。1 ずつ増やすことはできません。レベルを 1 ずつ上げています。繰り返しますが、呼び出しLevel.level_up(self)もあまり意味がありません...

Levelですので、あたかもそれをインターフェイスのように使用して、そこから継承Player(および他のサブクラス) する必要があると思いますが、よくわからないので、とにかく学ぶためにここにいるので、質問することにしました。私は何をすべきか?Levelで使用する最も適切な方法は何Playerですか?

4

5 に答える 5

4

「クラス A はクラス B ですか、それともクラス A にはクラス B がありますか?」という質問を自問するようにあなたに言ったのは私だと思います。、だから私はこの質問に答えなければならないような気がします。

あなたのレベルが実際に何をするかは 100% わかりませんが、ポケモン、ワールド オブ ウォークラフト、リーグ オブ レジェンド、その他何千ものゲームで使用されているものと似ていると思います。もしそうなら、あなたはすでにあなたのLevel-class を間違えています。そのようなものであってはなりません。

あなたは確かに1つのことで正しいです。 「プレーヤーは確かにレベルではありません」 他の人がすでに述べたように、has-a関係を使用する必要があります。プレイヤーにはレベルがあります。私たち二人ともそれを知っています。ただし、プレイヤーには type の属性がなく、クラスの数値を保持Levelする整数属性があると言っています。levelLevel

これはすでにいくつかのベルを鳴らしているはずですが、ここにヒントがあります。これは、内部で呼び出される -type 属性Nameを持つ -class を持つことと同じです。stringname

したがって、答えは次のとおりです。 クラスは、その値を保持する属性を内部に持つのではなく、Nameすでに文字列自体である必要があり、から継承する必要があります。同じことがあなたにも当てはまります。それはすでに整数自体なので、から継承し、次にとそのメソッドを追加します。stringstringLevelintexp

player.levelこれで、プレイヤーのレベルの整数値を返すために使用できます。を取得するにはexp、 を「使用する必要があります」player.level.exp。奇妙に聞こえるかもしれませんが、expIS はレベルの属性であるため、「必要」を引用しました。基本的に数値の小数点と同じですよね?

また、次のようなものを呼び出すことは、player.level.increase()今でははるかに理にかなっています。すでに整数値ですが、なぜそうしないのplayer.level += 1ですか? また、追加の中に高度な機能が必要な場合は、Level.__add__(self, value)メソッドをオーバーライドするだけです。なぜこれが必要ないのか、理由は一つも思いつきません。required_exp(すでにプロパティを作成しているのではありません)

于 2013-05-10T20:46:02.110 に答える
2

Player がレベルではないことがすでにわかっている場合、継承は正しいメカニズムではありません。継承は「車は乗り物、バイクは乗り物」のような関係で機能するため、そのような状況では、車とバイクは両方とも車のサブクラスです。

ただし、この関係は、レベルが独自の機能を持つ別のクラスとして表現されるべきではないという意味で、実際の構成にも適合しません。プレーヤーにレベルがあることは事実ですが、player.level_up()ご指摘のとおり、これらのメソッドをオブジェクトplayer.add_experience()で呼び出すよりも明確です。levelこれは、プレーヤーのレベルとの相互作用が、 ではなく、そのメソッドを介して意味を持つためplayer.level.levelです。次に、Level クラスの機能を Player に移動することを検討する必要があります。

クラス図

于 2013-05-10T20:54:59.550 に答える
0

レベルとそのレベルに関する追加経験の両方を追跡する代わりに、単純に合計経験を追跡することができます。

合計経験値から、レベルと次のレベルに到達するために必要な経験値の量、またはその他の興味のある量を導き出すことができます。

例えば、

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
于 2013-05-10T21:48:36.430 に答える
0

プレーヤーは間違いなくレベルではありませんが、彼にはレベルがあります。レベルの一部であるプレーヤーのすべての重要な情報を追跡するため、プレーヤークラスで上記で定義されたレベルクラスを使用しても問題はありません。

于 2013-05-10T20:41:32.653 に答える