2012-06-08 7 views
3

Я не знаю, как это называется, я считаю, что это примеры.Экземпляры классов на PHP?

Предположим, у нас есть класс «Монстр». Этот класс должен содержать значение «Здоровье». Он установлен на «5» при создании класса. Он также должен содержать уникальное значение идентификатора для каждого монстра.

Я думаю о чем-то вроде этого:

$monster_1 = new Monster(); //sets monster ID to 1 
$monster_2 = new Monster(); //sets monster ID to 2 
$monster_3 = new Monster(); //sets monster ID to 3 

Итак, давайте скажем, я хочу, чтобы вычислить общее HP всех монстров.

$totalHp = $monster_1->getHp() + $monster_2->getHp() + $monster_3->getHp(); 

Он также будет работать, но что, если я добавляю новый монстр по имени $monster_4. Я должен был бы добавить его к вычислению $ totalHp вручную.

Я мог бы сделать массив вместо $monster переменных и вычислить $ totalHp с Еогеаспом - но это выглядит странно ...

Я не знаю, как это делается на других языках.

Есть ли другой способ архивировать это?

Ps. Я пытаюсь получить логику «http://www.scirra.com/demos/ghosttutorial/». Вы создаете класс Monster, и каждый Monster использует этот класс в качестве экземпляра. Мое решение, безусловно, сработает, но я не уверен, что это хакерский способ архивировать это.

+0

Вы можете сделать это с помощью 'eval()', но это было бы довольно взломанным. Кажется, ваш массив лучше всего подходит, я бы сказал, иди с ним. – Steve

+9

не использовать eval(), никогда. –

+2

Хранение всех монстров в массиве - прекрасное решение. – alexn

ответ

3

Создайте класс-помощник, который содержит набор монстров, возможно, класс MonsterTeam;

class Monster { 
    ... 
} 

class MonsterTeam { 
    private $_monsters = []; 

    public function addMonster(Monster &$monster) { 
     array_push($this->_monsters, $monster); 
    } 

    public function getTotalHp() { 
     $hp = 0; 

     foreach ($this->_monsters as $monster) { 
      $hp += $monster->getHp(); 
     } 

     return $hp; 
    } 
} 


$team = new MonsterTeam(); 

$monsterA = new Monster(); 
$team->addMonster($monsterA); 

$monsterB = new Monster(); 
$team->addMonster($monsterB); 

echo "Total HP: " . $team->getTotalHp(); 
+0

Зачем вы передаете объект по ссылке? Я не думаю, что это важно в объектах. –

+0

Это правильный ответ. Вам нужен объект коллекции, который поддерживает ** Dependency Injection **, чтобы вы могли добавлять в группу всевозможные монстры. Затем удалите ссылочный указатель и укажите класс 'Monster' как абстрактный класс, который будет расширен каждым типом монстра. – Xeoncross

+0

Этот ответ требует, чтобы любой код, создающий монстра, также имел доступ к «MosterTeam». Отметьте мой ответ. –

1

Вы можете использовать объект, который действует как контейнер для монстров и использовать, чтобы следить за вами:

class MonsterContainer 
{ 
    private $monsters = array(); 

    public function __construct() 
    { 
     // do stuff 
    } 

    public function addMonster(Monster $monster) 
    { 
     $this->monsters[] = $monster; 
    } 

    public function totalMonstersHP() 
    { 
     $hp = 0; 
     foreach ($this->monsters as $monster) 
     { 
      $hp += $monster->getHp() 
     } 
     return $hp; 
    } 
} 

$monster_1 = new Monster(); 
$monster_2 = new Monster(); 
$monster_3 = new Monster(); 

$container = new MonsterContainer(); 
$container->addMonster(monster_1); 
$container->addMonster(monster_2); 
$container->addMonster(monster_3); 
echo $container->totalMonstersHP(); 
+0

Вот так! Maby 'class Monster extends Enemy' –

+5

Это нарушение инкапсуляции. –

+0

так много с OZ_ на этом –

2

Прежде всего, они называются объекты или Экземпляры, как в Объект Ориентированное программирование?

Во-вторых, ничто не мешает вам создать массив (это не выглядит странно) монстров:

$monsters = array(
    new Monster(), 
    new Monster(), 
    new Monster(), 
    new Monster() 
); 

foreach($monsters as $monster) { 
    $totalHP += $monster->hp; 
} 

О уникальный идентификатор, который один должен нести ответственность за MonsterFactory, а это означает, монстр должен быть присвоен идентификатор, он не должен присвоить его себе, скорее, ID должен соответствовать . Что-то вроде этого при создании монстра:

new Monster(4); //ID is 4 

Кто отслеживает его? Кто-то другой, а не монстр.

+2

Экземпляры - это совершенно допустимый термин ... –

+0

@Matthieu: Согласен. Исправленный. –

0

I второй alexn, используя массив для хранения экземпляров класса (да, это правильный термин) отлично.

Затем вы можете использовать foreach, чтобы рассчитать общий HP.

0

Создать класс MonstersCollection, который будет содержать методы getNewMonster() и getTotalHP().

псевдокод:

class MonstersCollection 
{ 
    private $Monsters; 

    public function getNewMonster() 
    { 
     $Monster=new Monster(); 
     $this->monsters[]=$Monster; 
     return $Monster; 
    } 

    //and you know how to write method to get total HP :) 
} 
+0

Итак, вы сделали фантастический массив? –

+0

Это не элегантный способ сделать это, по крайней мере, вам нужно сделать '__construct' частным, чтобы никто другой не мог создавать монстров. –

+0

@JuanMendes согласен, более правильный код в ответе Бьорна - вот только пример, чтобы показать идею. –

1

Вы можете создать $monsters массив так:

$monsters = array(); 

Тогда каждый раз, когда вы хотите добавить монстра, вы делаете это:

$monsters[] = new Monster(); 

После этого вы можете пройти через свой массив, чтобы получить общие хитпоинты:

$totalHP = 0; 
foreach($monsters as $monster) { 
    $totalHP += $monster->getHp(); 
} 

Где после этого цикла $totalHP будет содержать полные хитпоинты всех монстров в вашем массиве.

+0

Это не очень гибко, вам нужно будет обновить этот массив из любого места в коде, который удаляет или удаляет монстра. –

+0

@JuanMendes. Тем не менее, более гибкая, чем наличие отдельной переменной ($ monster_1, $ monster_2 и т. Д.) Для каждый монстр, нет? Его вопрос заключался не в гибкости, а в том, «как мне все переписать?» Речь шла о том, как рассчитать оставшееся здоровье для группы монстров. Вот и все. – Crontab

-2

Возможно, вы можете создать новый класс или функцию в том же классе монстров , который вызывается в конструкторе, и каждый раз, когда класс создается , он вызывает глобальную переменную, которая увеличивается.

+0

Нет, не используйте глобальные переменные. Вычисление идентификатора не является обязанностью класса Monster. –

-2

Вы можете создать шаблон наблюдателя, который может автоматически обновлять свойство totalHp в централизованном объекте при создании экземпляра Monster.

Но быстрее/проще всего было бы что-то подобное в вашем Монстров классе:

class Monster { 

    ... 
    private $hp = 5; 
    private static $totalHp = 0; 
    ... 

    public function getHp() { 
     return $this->hp; 
    } 

    public function __construct(...) { 
     ... 
     self::totalHp += $this->getHp(); 
     ... 
    } 

    public function __destruct(...) { 
     ... 
     self::totalHp -= $this->getHp(); 
     ... 
    } 

    ... 

    public static function getTotalHp() { 
     return self::totalHp; 
    } 

    /** 
    * Provide negative number to reduce HP or positive to increase HP. 
    */ 
    public function alterHp($hp) { 
     $this->hp += $hp; 
     self::totalHp += $hp; 
    } 
} 

Затем, чтобы получить текущее значение totalHp вы должны сделать следующее в коде клиента:

$totalHp = Monster::getTotalHp(); 
+1

Тот же комментарий, что и для ответа Джона Конде –

+0

Я проголосовал за это, но он хрупкий, что, если 'getHp()' изменяется? Было бы лучше отслеживать все экземпляры и вызывать 'getHp()' для всех из них при вызове getTotalHp. –

+0

Это быстрый пример кода. Я не собираюсь реализовывать здесь все приложение. И в идеале getHp() должен быть только получателем для свойства $ hp. Ничего больше. – scaraveos

1

Вы можете создать завод по сборке; он будет отвечать за создание новых монстров. Слияние двух классов вместе, как правило, не мое, но мне нравится тот факт, что я могу сделать конструктор таким же:

Он использует две статические переменные (прославленный глобальный, я полагаю), один для идентификатора монстра и один для сбор монстров, используя SplObjectStorage.

Методы, необходимые для итерации по всем монстрам, используют метод each(), поэтому любая логика, которую вы хотите, может быть определена вне класса.

class Monster 
{ 
    private $id; 
    public $health; 

    private static $instances; 
    private static $nextid = 1; 

    // private constructor 
    private function __construct($id) 
    { 
    $this->id = $id; 
    $this->health = 5; 
    } 

    public static function create() 
    { 
    if (!self::$instances) { 
     self::$instances = new SplObjectStorage; 
    } 
    $o = new self(self::$nextid++); 
    self::$instances->attach($o); 

    return $o; 
    } 

    public static function remove($o) 
    { 
    if (!self::$instances) { return; } 
    self::$instances->detach($o); 
    } 

    // iterate over all objects 
    public static function each($cb) 
    { 
    if (!self::$instances) { return; } 
    foreach (self::$instances as $o) { 
     $cb($o); 
    } 
    } 
} 

Небольшой пример использования

$m1 = Monster::create(); 
$m2 = Monster::create(); 

$total_health = 0; 
Monster::each(function(Monster $m) use (&$total_health) { 
    $total_health += $m->health; 
}); 
echo "Total health: $total_health\n"; 
-1

Это весьма характерно для классов, чтобы следить за его экземпляров.

class Monster { 
    private $monsters = array(); 
    public function __construct() { 
     self::monsters[] = $this; 
    } 

    public function __destruct() { 
     array_splice(self::monsters, array_search($this, self::monsters), 1); 
    } 

    public static function getTotalHp() { 
     $total = 0; 
     foreach(self::monsters as $monster) { 
      $total += $monster->getHp(); 
     } 
     return $total; 
    }  
} 
+2

Это делается для каждого цикла каждый раз, когда вызывается getTotalHp(). На самом деле это не то, что я бы назвал хорошей практикой. Метод __destruct() выглядит очень медленным, а также требует поиска и сращивания массива. Наконец, ваше свойство $ monsters не статично, но вы используете его как статический контекст в getTotalHp(). – scaraveos

+0

@scaraveos Почему это не хорошая практика? Это не займет много времени, и вам не нужно обновлять общее значение при каждом изменении hp. Преждевременная оптимизация, если вы меня спросите. Потерял ваш взлет! –

+0

«Его не собираются долго» - не оправдание. Подобные практики в конечном итоге будут добавлены в приложение реального мира, и результаты не будут хорошими (или быстрыми). – scaraveos

Смежные вопросы