PHP:OOP设计以及如何在类似的类中重用方法


PHP: OOP design and how to reuse a method across similar classes

我熟悉扩展父类,但我迷失了如何创建一个从父类继承工作方法的类,该类可能会根据它所在的类而更改。例如,我有一个名为 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 Patternhttp://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) {}