这种设计模式是什么,它的缺点是什么?

时间:2013-11-05 15:05:57

标签: php design-patterns

我已经在一个大型项目上工作了大约一年,最近我开始使用新模式来显示数据。

背景

我有许多派生类将数据包装在1:1链接的sql表及其相应的基类中。我的目标是将任何和所有显示代码保持在业务逻辑中,并且任何和所有SQL /业务逻辑都远离显示代码。我认为这在我的案例中是很好的做法,使代码更加模块化,并允许引入不同的显示媒体。我遇到的一个问题是,数据类具有通用显示功能更合乎逻辑,其中实际的显示介质(html,json,xml)可能会在以后添加。我在一些类中有一些递归绘图函数会使绘制函数排除非常困难。我的第一个想法是为我想要显示的每种类型创建另一个派生类,它只是以所需的方式实现显示功能,但这打破了我所遵循的另一种模式。我使用工厂方法来实例化大多数这些类。提供了一个ID,它从数据库中提取元数据,以便知道哪个表以及应该链接到哪个相应的类。所以,在这种情况下,我需要知道我在显示它之前显示的内容(HTML,JSON等等),这在我的情况下也不会起作用,因为它会破坏工厂。

我的解决方案

我创建了一个静态类,其中包含每个显示媒体的“显示器”功能。在这一点上,我正在利用这个类作为更多的容器。此“dispalyer”类中的函数返回一个匿名函数,该函数将显示所需类的实例。它返回它从对象成员构建的任何可显示数据字符串。这样我就可以在我的任何课程上调用.display(),并简单地将其传递给所需类型的显示器:page->display(PageDisplayer::asHTML());

我认为它看起来很干净,并且允许逻辑与显示代码分开,同时将特定的显示代码保存在一个有组织的区域中。

下面是一个非常简单的示例,不包括我正在处理的所有工厂方法和继承级别。 (这段代码有错误,我没有在工作环境中写这个 - 它可能不会“编译”)

主要逻辑/模型

<?php
class UserData {
    private $ID;
    private $name;

    public function __construct($ID, $name) {
        $this->ID = $ID;
        $this->name = $name;
    }

    public getID() {
        return $this->ID;
    }

    public getName() {
        return $this->name;
    }

    public function display($displayer) {
        return $dispalyer($this);
    }
}
?>

显示器类

<?php
class UserDataDispalyer {

    static function asHTML() {
        return function($userData) {
            $out = '<div id="' . $userData->getID() . '">';
            $out .= $userData->getName();
            $out .= "<div>";
            return $out;
        }
    }

    static function asJSON() {
        return function($userData) {
            return json_encode(array("ID" => $userData->getID(), "name" => $userData->getName()));
        }
    }
}
?>

这是前端渲染代码的样子

HTML页面

<html>

<?php
$userData = new UserData(12345, "John");
echo $userData->display(UserDataDispalyer::asHTML());
?>

</html>

JSON API

<?php
$userData = new UserData(12345, "John");
echo $userData->display(UserDataDispalyer::asJSON());
?>

问题

最后,我的实际问题:这是一个已知的设计模式吗?我缺少哪些主要缺点?我不应该使用这个吗?

1 个答案:

答案 0 :(得分:2)

我认为你所做的事情没有名字,而且确实不应该这样。这是何时使用界面和strategy pattern的教科书示例。

您的方法的缺点是您可以将任意函数传递给display并获得各种错误。使用接口,确保传递给display的唯一参数是某种类型(下面,类型是UserFormatter)。

以下是相同代码的示例,但使用的是接口。

interface UserFormatter {
  public function get($user);
}

public HTMLFormatter implements UserFormatter {
  public function get($user) {
    return "<div id=\"{$user->getID()}\">{$user->getName()}</div>";
  }
}

public JSONFormatter implements UserFormatter {
  public function get($user) {
    return json_encode(array('ID'   => $user->getID(),
                             'name' => $user->getName()));
  }
}

userData课程中,您将拥有

public function display(UserFormatter $formatter) {
        return $formatter->get($this);
    }

此外,您的userData课程应命名为UserData。类总是在CamelCase中。