ООП подход для упаковки подклассов строк базы данных - PullRequest
2 голосов
/ 22 августа 2011

Допустим, я хочу хранить собак в таблице базы данных, у каждой собаки есть свой подкласс в PHP.

В основном я хочу избежать хранения / перечисления имен подклассов в разных местах кода. Какой подход к этому был бы хорош для ООП?

abstract class Dog {
    protected $data;
    public function __construct($data) {
        $this->data = $data;
    }
    public function name() {
        return $this->data["name"];
    }
    abstract public function breed();
}

class GermanShepherd extends Dog {
    public function breed() {
        return _("German Shepherd");
    }
}

class BullDog extends Dog {
    public function breed() {
        return _("Bulldog");
    }
}

Теперь у меня есть этот класс, который обрабатывает группы объектов (т.е. собак):

class Dogs {
    public static function getDogs() {
        // ...
        $ret = array();
        while ($row = mysql_fetch_assoc()) {
            switch ($row["type"]) { // I could do this using a lookup array
                 case "shepherd": $dog = "GermanShepherd"; break;
                 case "bulldog": $dog = "Bulldog"; break;
            }
            $ret[] = new $dog($row);
        }
        return $ret;
    }
}

И я хотел бы использовать этот класс, чтобы получить типы собак в моем представлении (особенно для формы add dog ) вместо перечисления имен классов:

?><form><select name="type"><?php
foreach (array("GermanShepherd", "Bulldog") as $dog) { // here I would like to do avoid listing the class names again
    ?><option value="<?=$dog ?>"><?php
    $d = new $dog; // actually I can't instantiate the class here because I don't have any data at this point
    echo $d->name();
    ?></option><?php
}
?></select></form><?php

Я хотел бы включить это в класс Dogs, что-то вроде этого:

class Dogs {
    private static $dogs = array(
        "shepherd" => "GermanShepherd",
        "bulldog" => "Bulldog",
    );
    public static function getDogs() {
        // ...
        $ret = array();
        while ($row = mysql_fetch_assoc()) {
            $dog = self::$dogs[$row["type"]];
            $ret[] = new $dog($row);
        }
        return $ret;
    }

    public static function getDogTypes() {
        return array_values(self::$dogs);
    }
}

?><form><select name="type"><?php
foreach (Dogs::getDogTypes() as $dog) {
    ?><option value="<?=$dog ?>"><?php
    $d = new $dog; // here I still need to instantiate the class and I don't have any data to provide it with
    echo $d->name();
    ?></option><?php
}
?></select></form><?php

Пока что это будет работать, но что, если мне понадобится больше информации, специфичной для класса, например, когда у меня будет больше полей, специфичных для типа собаки?

foreach (Dogs::getDogTypes() as $dog) {
    $d = new $dog; // instantiate again?
    foreach ($d->formFields() as $f) { // I wouldn't do it like this, just putting this here for demonstrative purposes
        echo $f;
    }
}

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

Спасибо за ваши идеи!

Ответы [ 3 ]

2 голосов
/ 22 августа 2011

Сначала используйте Интерфейсы .Это покажет вам, что наличие более специфичных интерфейсов (различных методов и свойств класса для подкласса) заставит вас по-разному обращаться с ними по-конкретному.Таким образом, они покажут вам, где имеются недостатки, и позволят упростить ваши объекты во что-то более пригодное для повторного использования.

Пока ваши объекты хранят только некоторые данные, используйте объект передачи данных вместо - какой-либо "тип".Так что вам не нужно иметь дело с типом.Тем не менее, вы также можете использовать StdClass или Array для этого, если хотите сохранить его базовым.Плюсом является то, что вам не нужно писать столько кода.

В случае, если этого недостаточно (как это будет), добавляйте код только тогда, когда это необходимо.Тогда все должно быть проще в долгосрочной перспективе.Итак, начните с базового класса объектов передачи данных и опирайтесь на него.

Поэтому используйте классы, которые вы пишете, для разделения проблем, а не для переплетения проблем.Инкапсулируйте то, что меняется, чтобы ваш код действительно мог выиграть от вашего дизайна.

1 голос
/ 22 августа 2011

Я думаю, что статический массив в вашем классе Dogs является вполне приемлемым решением.Это не относится к проблеме создания экземпляров, но вы можете исправить это с помощью (статического) фабричного метода.Чтобы сделать создание экземпляров еще проще и масштабируемее, вы можете убедиться, что хранимые строки каким-то образом отображаются на имена объектов:

$dog = 'Dog' . ucfirst( $row['type'] );
$ret[] = new $dog;

Я не думаю, что метод ->getFormFields() вообще плохая идея;если поля различаются в зависимости от типа собаки, было бы совершенно правильно включить это в объект!

0 голосов
/ 22 августа 2011

Как насчет хранения ваших собак в двумерном массиве?

while ($row = mysql_fetch_assoc()) {
  switch ($row["type"]) { // I could do this using a lookup array
    case "shepherd": 
      $dog = "GermanShepherd"; 
      break;
    case "bulldog": 
      $dog = "Bulldog"; 
      break;
  } // switch

  $ret[$row["type"]][] = new $dog($row);
} // while
...