适用于ActiveRecord类的模式

Uns*_*tal 15 php oop activerecord

我有一个ActiveRecord BaseModel类和许多继承它的类模型.而且我有一个类Bookmark,也是继承的BaseModel.此外,我有Decorator-inherited类,他们实现了特殊的接口来表示单个模型(getModelView(model)方法).这是一些伪代码:

TestModel inherits BaseModel
    getName:
        return this.name

BookmarkModel inherits BaseModel
    BaseModel model

    getBookmark:
        return this.model

TestDecorator inherits BaseDecorator implements SingleModelViewInterface:
    getView(model):
        return 'view' //html-view of model

BookmarkDecorator inherits BaseDecorator
    getBookmarksView(BookmarkModel[] bookmarks):
        foreach(bookmarks > bookmark):
            decorator = Relation::getDecoratorByModel(bookmark->getEntityType())
            decorator->getView(bookmark->getBookmark())
Run Code Online (Sandbox Code Playgroud)

所以,一切看起来都不错,直到我想稍微更改该书签模型的View.我想要为该视图添加自定义标题.而且我无法在装饰器内部制作它,因为它不仅仅是用于书签.

编辑:所以,问题是 - 似乎我需要一个装饰模式,但我没有任何东西可以继承,因为具体的TestDecorator使用TestModel的特殊方法.所以现在我使用魔术方法(PHP)完成了一些非常糟糕的实现:

class BookmarkedModel {

    /** @var BaseEntityModel*/
    private $model;

    public function __construct(BaseEntityModel $model) {
        $this->model = $model;
    }

    public function getName() {
        return 'Bookmark '.$this->model->getName();
    }

    public function __call($name, $arguments) {
        return call_user_func_array(array($this->model, $name), $arguments);
    }

    public function __get($name) {
        return $this->model->$name;
    }

    public function __set($name, $value) {
        return $this->model->$name[$value];
    }

}
Run Code Online (Sandbox Code Playgroud)

所以它现在可以工作,但就代码结构,可读性和稳定性而言,这是一个非常糟糕的决定.

Rya*_*efi 2

模型应该不知道视图。模型代表了从各个角度同时看到的原始数据。该视图是该模型的透视图。控制器应该将模型提供视图:

$model_view->render($model);
Run Code Online (Sandbox Code Playgroud)

然后装饰视图:

$bookmark_view->render($model); // bookmark_view wraps a model_view,
// returns 'Bookmark '.$this->model_view->render($model)
Run Code Online (Sandbox Code Playgroud)

仅基于接口而不是类型进行装饰。

PHP 的魔术方法很棒,但它们不应该用于 ActiveRecord,这违背了“关注点分离”,在这种情况下将模型与其持久性机制分开。

相反,创建一个 ActiveRecord 对象并将模型提供它。

$record->store($model);
Run Code Online (Sandbox Code Playgroud)

然后如果你需要修改存储,同样只需装饰存储机制:

$log_record->store($model); // wraps $record, logs a message prior to database storage.
Run Code Online (Sandbox Code Playgroud)