1

我熟悉扩展父类,但我不知道如何创建一个从父类继承工作方法的类,这可能会根据它所在的类而改变。例如,我有一个名为 Log_Metadata 的模型类存储日志元数据的数据库表。我还有一个名为 Station_Metadata 的类,用于存储电台元数据的表。除了站点或日志的 ID 的控制字段之外,表模式是相似的,但模式的其余部分是相同的,因为每个元数据行都有一个 ID、一个 meta_key 列和一个 meta_value 列。

我基本上想为这些模型创建一个通用方法,允许我跨各种模型添加/编辑/删除元数据。在这种情况下使用抽象类或接口是否相关?如果事物的模型端有所不同,我该如何覆盖该方法?

4

2 回答 2

2

我不确定这实际上是你应该如何设计的。听起来您应该从保存数据的类中抽象出常用方法(也许您想使用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';
    }
}

同样,这只是一种您可以适应您的需求的模式。

于 2013-10-31T23:14:33.637 回答
0

对于初学者来说,这应该是您的初始设置;

  • 元数据(接口,在任何共享条件下定义元数据的基础知识)
  • MetadataAbstract(实现元数据,接口并提供所有元数据共享的基本方法)
  • Metadata\Log(添加属性和记录特定方法)
  • Metadata\Station(添加属性和...)

此外,您可能需要考虑将表结构更改为更像

  • 元数据(共享列)
    • Metadata_Log(特定于日志)
    • Metadata_Station(站特定)

这两个特定表都与您的元数据表 (1-1) 有关系。然后,您可以查询 metadata_log / metadata_station 表并加入主元数据表的结果。

正如其他人建议的那样,实现像 Doctrine2 这样很棒的东西会通过鉴别器映射来解决这个问题。但是它可能超出您的应用程序的范围?

我希望这能给你更多的见解:-)

编辑 1 _Did this on the quick tour ...所以如果我错过了什么,请打扰我,我想这就是你的意思。前提是除了命名之外没有您的具体细节的“具体”实现。

<?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) {}
于 2013-10-31T23:13:49.673 回答