Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern to use

I want to make the program with the following classes: Class Player, which stores some information about players with get/set functions. Player can be as AttackPlayer, which will have own data with get/set functions. Also Player can be as ProtectorPlayer, also with some other own data with get/set functions different than in AttackPlayer.

Also Player can be TeamPlayer or FreePlayer, each of these classes have own data etc.

The question is how to implement the hierarchy correctly?

At first I thought about multiple inheritance, which is not good anyway. Something like: Player AttackPlayer extends Player ProtectorPlayer extends Player

TeamPlayer extend AttackPlayer or ProtectorPlayer FreePlayer extend AttackPlayer or ProtectorPlayer

Also I thought something about strategy pattern, but it is not applicable here, because there are no common algorithms.

Are there any approaches which helps to organize such interaction?

Another way to do it is to have a field in the Player class, which helps to identify wether the TeamPlayer/FreePlayer is Attack or Protector type, and access appropriate fields depending on that. In this case inheritance would be like this:

Player TeamPlayer extends Player FreePlayer extends Player

Attack, Protect structs or classes without inheritance, but as fields in Player class.

But I don't like such an approach and I am searching for a better design.

like image 363
maximus Avatar asked Nov 21 '25 15:11

maximus


2 Answers

IMHO inheritance is the wrong model for this. Instead I would have a player class and different roles for it. It depends if a player can have multiple roles at the same time. I would use a strategy pattern.

like image 172
Udo Klein Avatar answered Nov 24 '25 07:11

Udo Klein


How about composition and interface/dependency injection ?

<?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;
}

Executing this will yield:

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

EDIT: updated to add a __toString() to the interface, an easy example of method composition.

like image 30
smassey Avatar answered Nov 24 '25 06:11

smassey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!