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 を実装し、すべてのメタデータが共有する基本メソッドを提供します)
  • Metadata\Log (プロパティを追加し、特定のメソッドをログに記録します)
  • Metadata\Station (プロパティを追加して ... )

さらに、テーブル構造をより似たものに変更することを検討することをお勧めします

  • メタデータ (共有列)
    • Metadata_Log (ログ固有)
    • Metadata_Station (ステーション固有)

両方の特定のテーブルがメタデータ テーブル ( 1-1 ) と関係を持っている場合。その後、metadata_log/metadata_station テーブルにクエリを実行し、メインのメタデータ テーブルの結果を結合できます。

他の人がDoctrine2と同じくらい素晴らしいものを実装することを提案しているように、ディスクリミネーターマッピングでこれを処理します。ただし、アプリケーションの範囲外である可能性がありますか?

これにより、さらに洞察が得られることを願っています:-)

編集 1 _クイック ツアーでこれを行いました...何かを見逃した場合はバグを報告してください。これがあなたの言いたいことだと思います。命名以外にあなたの仕様の「具体的な」実装がない場合。

<?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
        }
    }

上記の例では、abstract のすべての子クラスが getKey() メソッドを実装する必要がありますが、getValue() はオプションです。

ただし、後でこれを保存する場合は、次のことができます。

    if ($object instanceof Metadata) {}

    if ($object instanceof LogMetadata) {}
于 2013-10-31T23:13:49.673 に答える