用于包装数据库行子类的 OOP 方法
Posted
技术标签:
【中文标题】用于包装数据库行子类的 OOP 方法【英文标题】:OOP approach for wrapping subclasses of database rows 【发布时间】:2011-08-22 11:11:41 【问题描述】:假设我想将狗存储在一个数据库表中,每只狗在 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;
我想使用这个类来获取我视图中的狗类型(尤其是对于 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;
我认为部分问题在于我需要能够在有和没有数据库数据的情况下使用我的类:当我有来自数据库表的数据时,一切似乎都很合理,但我也需要数据我在创建新狗时生成表单。
感谢您的想法!
【问题讨论】:
【参考方案1】:首先使用Interfaces。这将向您展示拥有更具体的接口(每个子类不同的类方法和属性)将使您需要以不同的方式处理它们。因此,它们会向您展示不足之处,并使您能够将对象简化为更可重用的东西。
只要您的对象仅存储一些数据,请改用data transfer object - 它是任何“类型”。所以你不需要处理类型。但是,如果您想保持基本功能,也可以使用StdClass
或Array
。好处是:您实际上不需要编写那么多代码。
如果它还不够(因为它会),请仅在需要时添加代码。从长远来看,应该让事情变得更简单。因此,从一个基本的数据传输对象类开始并在其上构建。
因此,使用您编写的类来分离关注点,而不是交织关注点。封装变化的内容,以便您的代码实际上可以从您的设计中受益。
【讨论】:
感谢您的输入,您能否添加一个小代码示例以便我更好地理解您的意思?谢谢! 这将要求您用简单的话来创造您实际尝试通过您的应用程序实现的目标。从你给出的代码我不能说。我看到了:从数据库中读取结构化数据并将其输出到 html 中;拥有结构化数据列表。这是非常抽象的并且已经编码,因此不太适合具体示例,因为您甚至可以使用数组和标准函数来做到这一点,这不是一个有用的 OOAD 示例。所以也许你可以用简单的句子添加你想对你的问题做的事情? 让我想到的问题是向数据库添加新对象时:我需要检索可能的类型(=子类)以在表单中显示。对象共享代码(因此是 Dog 类的子类)。 好吧,如果狗没有区别,那么您根本不需要任何子类。给他们一个“种族”属性或任何被称为狗的东西,然后把它的名字放在那里。看起来这是唯一不同的地方。 只需创建一个狗类,您的代码会根据比赛领域而有所不同。应该做的工作不让事情对你来说太复杂。也可以为狗创建一个界面,以便您以后可以更轻松地进行更改。【参考方案2】:我认为 Dogs 类中的静态数组是一个可以接受的解决方案。它不涵盖实例化问题,但您可以使用(静态)工厂方法解决该问题。为了使实例化更加容易和更具可扩展性,您可以确保存储的字符串以某种方式映射到对象名称:
$dog = 'Dog' . ucfirst( $row['type'] );
$ret[] = new $dog;
我不认为->getFormFields()
方法是一个坏主意。当每个 Dog 类型的字段不同时,将其合并到对象中将是完全有效的 OO!
【讨论】:
【参考方案3】:将您的狗存储在二维数组中怎么样?
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
【讨论】:
嗯,我无法理解的是在实例化对象之前使用数据,即为用例“添加新狗”生成表单 你必须使用一些外部容器的东西。如果您按类别列出狗,则必须首先收集类别,无论您将类别存储在单独的列表中还是稍后从对象中提取类别信息。这就是为什么我说,存储预先分类的东西。多余的?是的。谁在乎。您可以使用 Dog 工厂设置一个智能 DogList 类。以上是关于用于包装数据库行子类的 OOP 方法的主要内容,如果未能解决你的问题,请参考以下文章