3

我想用以下类制作程序: 类Player,它存储有关具有 get/set 功能的玩家的一些信息。Player 可以是AttackPlayer,它将拥有自己的数据和 get/set 函数。Player 也可以作为ProtectorPlayer,也可以使用其他一些自己的数据,其获取/设置功能与AttackPlayer不同。

Player 也可以是TeamPlayerFreePlayer,每个类都有自己的数据等。

问题是如何正确实现层次结构?

一开始我想到了多重继承,反正也不好。类似于: Player AttackPlayer extends Player ProtectorPlayer extends Player

TeamPlayer 扩展 AttackPlayer 或 ProtectorPlayer FreePlayer 扩展 AttackPlayer 或 ProtectorPlayer

我也想过策略模式,但在这里不适用,因为没有通用的算法。

是否有任何有助于组织这种互动的方法?

另一种方法是在 Player 类中有一个字段,这有助于识别 TeamPlayer/FreePlayer 是 Attack 还是 Protector 类型,并根据它访问适当的字段。在这种情况下,继承将是这样的:

Player TeamPlayer 扩展 Player FreePlayer 扩展 Player

攻击、保护结构或类而不继承,但作为 Player 类中的字段。

但我不喜欢这样的方法,我正在寻找更好的设计。

4

5 回答 5

6

恕我直言,继承是错误的模型。相反,我会有一个玩家类和不同的角色。这取决于玩家是否可以同时担任多个角色。我会使用策略模式。

于 2013-06-07T07:01:24.150 回答
2

组合接口/依赖注入怎么样?

<?php

interface IPlayer {
    public function __toString();
}

class Player implements IPlayer {
    protected $_id;
    protected $_name;

    public function __construct( $id, $name ) { 
        $this->_id = $id;
        $this->_name = $name;
    }
    public function getId() { return $this->_id; }
    public function setId($id) { $this->_id = $id; }
    public function setName($n) { $this->_name = $n; }
    public function getName() { return $this->_name; }

    public function __toString() {
        return 'my name is ' . $this->_name . ' and my id is ' . $this->_id;
    }
}

class ComposedPlayer implements IPlayer {
    protected $_player;

    public function __construct( IPlayer $p ) {
        $this->_player = $p;
    }
    public function __set($k, $v) {
        $this->_player->$k = $v;
    }
    public function __get($k) {
        return $this->_player->$k;
    }
    public function __call($func, $args) {
        return call_user_func_array( array( $this->_player, $func ), $args );
    }
    public function __toString() {
        return $this->_player->__toString();
    }
}

class AttackPlayer extends ComposedPlayer {
    function getNameMod() {
        return 'attack player ' . $this->getName();
    }
    public function __toString() {
        return parent::__toString() . ' and im an attack player';
    }
}

class ProtectedPlayer extends ComposedPlayer {
    function getNameMod() {
        return 'protected player ' . $this->getName();
    }
    public function __toString() {
        return parent::__toString() . ' and im an protected player';
    }
}

class TeamPlayer extends ComposedPlayer {
    function getIdMod() {
        return $this->getId() - 10;
    }
    public function __toString() {
        return parent::__toString() . ' and im an team player';
    }
}

class FreePlayer extends ComposedPlayer {
    function getIdMod() {
        return $this->getId() + 10;
    }
    public function __toString() {
        return parent::__toString() . ' and im an free player';
    }
}

$free_attack_player = new FreePlayer( new AttackPlayer( new Player( 100, 'John' ) ) );
$free_protected_player = new FreePlayer( new ProtectedPlayer( new Player( 101, 'Bob' ) ) );
$team_attack_player = new TeamPlayer( new AttackPlayer( new Player( 102, 'Bill' ) ) );
$team_protected_player = new TeamPlayer( new ProtectedPlayer( new Player( 104, 'Jim' ) ) );

foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
    echo 'id: ', $p->getId(), ' name: ', $p->getName(), ' mod id: ', $p->getIdMod(), ' mod name: ', $p->getNameMod(), PHP_EOL;
}

foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
    echo $p, PHP_EOL;
}

执行此操作将产生:

id: 100 name: John mod id: 110 mod name: attack player John
id: 101 name: Bob mod id: 111 mod name: protected player Bob
id: 102 name: Bill mod id: 92 mod name: attack player Bill
id: 104 name: Jim mod id: 94 mod name: protected player Jim
my name is John and my id is 100 and im an attack player and im an free player
my name is Bob and my id is 101 and im an protected player and im an free player
my name is Bill and my id is 102 and im an attack player and im an team player
my name is Jim and my id is 104 and im an protected player and im an team player

编辑:更新以向接口添加 __toString(),这是方法组合的简单示例。

于 2013-06-07T10:41:02.400 回答
0

这可能是TDD非常方便的问题。这种方法起初看起来很慢,但在设计不明显时非常有用。TDD 倾向于使设计从代码本身中浮现出来。

如果你有兴趣尝试 TDD,你可以从我们公司教练写的这个博客开始。另外,如果可以的话,看看这里与 TDD 相关的两集(第 6a 和 6b 集):它们来自鲍勃叔叔,所以真的建议讲座/观看。

于 2013-06-07T07:15:53.440 回答
0

玩家可以是 TeamPlayer 或 FreePlayer

TeamPlayer 扩展 AttackPlayer 或 ProtectorPlayer FreePlayer 扩展 AttackPlayer 或 ProtectorPlayer

我认为,这种方法是可以的。考虑存储数据。如果您想将其存储在数据库中,这将是一个不错的方法:您拥有包含所有玩家数据的 Player 表,并创建其他表(扩展 Player 表)来存储不同类型玩家的数据。查看类表继承

其实继承层次可以大于1,但不能大于4。如果继承很明显,那没关系。主要规则是保持低复杂性。

另一方面,如果您不打算将此数据存储在 db 中或将播放器对象中的外键存储到 Free 对象等中,则在您的情况下似乎更明显 - 使用另一种方法。

于 2013-06-07T07:53:53.343 回答
0

它可以是工厂和策略的组合,如下所示:

玩家可以是团队玩家或自由玩家,可以使用攻击者或保护者策略进行游戏。因此自由玩家或团队玩家可以继承 Player 类,在它们中我们可以关联播放策略,可以是攻击者或保护者。所以在这种情况下,程序发起者可以调用工厂来决定玩家是自由玩家还是团队玩家,并可以传递策略来玩。在 Player 中将策略作为关联将有助于保持代码更具可扩展性以添加新策略。玩家类型的工厂与策略分开,因此可以独立扩展。使用过多的继承会导致代码的性能和维护问题。

请不要将“扩展”之类的词视为特定于 java 的。

于 2013-06-07T08:35:18.133 回答