0

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

背景

我有许多派生类将数据包装在 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>

<?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());
?>

问题

最后,我的实际问题是:这是一种已知的设计模式吗?我有什么主要缺点吗?我有理由不使用它吗?

4

1 回答 1

2

我不认为你正在做的事情有名字,而且真的不应该有。这是何时使用界面和策略模式的教科书示例。

您的方法的缺点是您可以将任意函数传递给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 中。

于 2013-11-05T15:14:45.183 回答