我熟悉扩展父类,但我迷失了如何创建一个从父类继承工作方法的类,该类可能会根据它所在的类而更改。例如,我有一个名为 Log_Metadata 的模型类,用于存储日志元数据的数据库表。我还有一个名为 Station_Metadata 的类,用于存储电台元数据的表。表架构与台站或日志的 ID 的控制字段相似,但架构的其余部分相同,因为每个元数据行都有一个 ID、一个meta_key列和一个meta_value列。
我基本上想为这些模型创建一个通用方法,允许我在各种模型中添加/编辑/删除元数据。在这种情况下,使用抽象类还是接口相关?如果模型端的内容有所不同,如何覆盖该方法?
我不确定这是否真的是你应该如何设计这个。听起来你应该从保存数据的类中抽象出常用方法(也许你想使用DataMapper
? 但是,如果您认为这种ActiveRecord
继承模式有意义,我认为您希望做这样的事情吗?
abstract class Base
{
public function add($data)
{
$something = do_stuff($this->getId($data));
}
abstract protected function getId($data);
}
class Derived extends Base
{
private $idKey = 'DerivedKey';
protected function getId($data)
{
return $data[$this->idKey];
}
}
http://php.net/manual/en/language.oop5.abstract.php
在您的情况下,您将拥有通用方法 (CRUD),但调用抽象受保护的方法以获取特定内容。
这是Template Method Pattern
http://en.wikipedia.org/wiki/Template_method_pattern
编辑:如果您认为您可能有添加额外列/元数据/等的类,您可以尝试另一件事。
abstract class Base
{
public function add($data)
{
$something = array();
$something[] = do_stuff($this->getId($data));
$something[] = do_stuff($this->getName($data));
$something[] = $this->additionalFields($data);
}
abstract protected function getId($data);
abstract protected function getName($data);
protected function additionalFields($data)
{
// no additional fields by default
}
}
class Derived extends Base
{
private $idKey = 'DerivedKey';
private $nameKey = 'DerivedName';
private $other = 'new thing';
protected function getId($data)
{
return $data[$this->idKey];
}
protected function getName($data)
{
return $data[$this->nameKey];
}
protected function additionalFields($data)
{
return do_foo($this->other, $data);
}
}
请记住,这些都是非常人为的示例,向您展示 OOP 模式。例如,我认为getId
可能更复杂。如果你有一些东西一直遵循这种模式,更好的设计可能只是:
class Base
{
protected $metadata = array(
'id' => 'defaultId',
'name' => 'defaultName'
);
public function add($data)
{
foreach ($metadata as $key => $value) {
do_something($key, $data[$value]);
}
}
}
class Derived extends Base
{
public function __construct()
{
$this->metadata['id'] = 'DIfferentId';
}
}
同样,这只是一种您可以适应自己需求的模式。
首先,这应该是您的初始设置;
- 元数据
- (接口,定义元数据是什么的基础知识,在任何共享条件中) 元数据
- 抽象(实现元数据,接口并提供所有元数据共享的基本方法)
- 元数据''日志(添加属性并记录特定方法)
- 元数据''工作站 ( 添加属性和... )
此外,您可能需要考虑将表结构更改为更像
- 元数据(共享列)
- Metadata_Log(特定于日志)
- Metadata_Station(特定站)
其中两个特定表都与元数据表有关系 ( 1-1 )。然后,您可以查询metadata_log/metadata_station表,并联接主元数据表中的结果。
正如其他人建议的那样,实现像 Doctrine2 这样令人敬畏的东西可以通过鉴别器映射来解决这个问题。但是,它可能超出了您的应用程序的范围?
我希望这能给你更多的见解:-)
编辑 1_Did快速浏览...所以如果我错过了什么,请打扰我,我想这就是你的意思。前提是除了命名之外,您的细节没有"具体"实现。
<?php
namespace Example;
interface Metadata {
function getKey();
function getValue();
}
abstract class AbstractMetadata implements Metadata {
abstract protected function getKey()
{
return 5;
}
protected function getValue()
{
return 3;
}
}
// use Example'AbstractMetadata;
class LogMetadata extends AbstractMetadata {
public function getKey()
{
return 1;
}
public function getValue()
{
return 2;
}
}
// use Example'AbstractMetadata;
class StationMetadata extends AbstractMetadata {
public function getKey()
{
return 2;
}
public function getValue()
{
return parent::getValue(); // 3
}
}
在上面的例子中,抽象的所有子类都必须实现getKey()方法,而getValue()是可选的。
然后稍后你要存储它,你可以:
if ($object instanceof Metadata) {}
if ($object instanceof LogMetadata) {}