假设我想将狗存储在数据库表中,每只狗在PHP中都有自己的子类。
基本上我想避免在代码中的不同位置存储/列出子类名。对此有什么好的OOP方法?
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;
}
}
我想使用这个类在我的视图中获取狗类型(特别是对于添加狗形式),而不是列出类名:
?><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;
}
}
我认为部分问题在于我需要能够使用带有和不带数据库数据的类:当我从数据库表中获取数据时,一切看起来都很合理,但我还需要数据时我在创建新狗时会生成表单。
感谢您的想法!
答案 0 :(得分:2)
首先使用Interfaces。这将向您展示具有更多特定接口(每个子类的不同类方法和属性)将使您需要以不同方式处理它们。因此,他们将向您展示缺陷的位置,并使您能够将对象简化为更易于使用的对象。
只要您的对象只存储一些数据,请使用data transfer object代替 - 这是任何“类型”。所以你不需要处理类型。但是,如果您想将其保持基本状态,也可以使用StdClass
或Array
。正面是:你不需要实际编写那么多代码。
如果它不够(原样),只需在需要时添加代码。从长远来看,应该让事情变得更简单。所以从一个基本的数据传输对象类开始并构建它。
因此,使用您编写的类来分离关注点,而不是交织关注点。封装各种不同的内容,因此您的代码实际上可以从您的设计中受益。
答案 1 :(得分:1)
我认为Dogs类中的静态数组是一个非常可接受的解决方案。它不包括实例化问题,但您可以使用(静态)工厂方法来解决此问题。为了使实例化更容易和更具可伸缩性,您可以确保存储的字符串以某种方式映射到对象名称:
$dog = 'Dog' . ucfirst( $row['type'] );
$ret[] = new $dog;
我认为->getFormFields()
方法根本不是一个坏主意;当每个Dog类型的字段不同时,将它合并到对象中是完全有效的OO!
答案 2 :(得分:0)
如何将您的狗存放在2D阵列中?
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