【发布时间】:2011-01-08 01:00:34
【问题描述】:
注意: 此问题已更新,以提供比以前更详细和更深入的信息。
更新: 我只想对所有回复的人说声谢谢。我仍然对哪种设计模式最适合小部件一无所知。也许是工厂模式或建造者模式之一?
我刚刚开始一个新项目,需要使用 MVC、OO 和设计模式。
想法如下:想象一个显示一组小部件的页面。这些小部件(通常)是基于数据库中几个单独表中包含的数据的图表。我使用了一个报告学生表现的页面运行示例。
高级要求
- 显示一组(仅限 HTML)小部件的页面。
- 小部件的数据将基于数据库查询。
- 该页面可用于查看包含类似布局数据的单独数据集。例如,单个页面将显示小部件,报告单个学生的各个方面的表现。
- 想看其他学生的表现,拉上另一页。不需要为不同的学生显示不同的小部件(尽管以后有可能会很好)。
- 可能有很多学生,但数据库中包含的数据对所有学生的布局类似。
- 可以轻松更改小部件的显示方式(例如将小部件从显示为饼图更改为显示为条形图)。
- 小部件应该能够快速创建。
低级要求
- 目前数据不会改变,因此小部件不需要自动更新。
- 小部件可以表示两种事物的比率(例如,以饼图形式表示的失败测试与成功测试的比率)、一系列点或有时是单个数值。
- 新小部件的开发应该轻而易举,无需修改现有代码。
- 要使用的框架:Zend 框架,基于 MVC。
定义一个小部件(至少)有三件事:要报告的数据集(在上面的示例中,学生 ID)、描述所报告指标的查询和呈现模式(条形图、时间序列等) .
下面是分解 MVC 每一层职责的方法:
视图: Zend 视图是注入了 PHP 的 HTML 模板。它们将包含几种类型的小部件之一。小部件有多种形式,包括:静态 JPEG 图像(从远程站点加载,即:<img src="http://widgetssite.com?x=2&y=3"/>、基于 JSON 的 javascript 小部件或各种图表(饼图、条形图等)
控制器: 创建小部件,然后将它们分配给视图。需要在某处维护要在页面上显示的一组小部件。由于我想不出在视图中执行此操作的好方法,因此我现在将其添加到控制器职责中。如果有更好的地方,请大声喊叫。控制器还必须处理任何其他输入参数并将它们传递给小部件。例如,data_set id 可以在 url 行传递为http:/.../report/?student_id=42
模型:Zend 框架中的模型负责提取数据,因此很可能包含用于访问数据库的每个小部件的类。
几点:
此处的模型代表特定小部件的数据。因此,它必须知道查询将是什么,以便将获取该数据所需的表汇集在一起。
在小部件可以呈现数据之前,很可能需要一个额外的处理步骤。这取决于将使用哪个渲染器。有时它可能需要从返回的数据中形成一个 url。其他时候,一个 JSON 数组。其他时候可能会创建一些标记。这可以在模型或控制器或视图中进行。除非有人能想到将其移至控制器或视图的充分理由,否则最好让它存在于模型中并保持视图和控制器的精简。
-
同样,一个小部件将由 3 个东西组成,它的参数、它的数据和它的渲染器。
问题的很大一部分是:在面向对象的设计中表示小部件的好方法是什么?我已经问过一次了,无法得到答案。 是否有一种设计模式可以应用于对这个项目最有意义的小部件?
这是 Widget 的一个相当简单的类的第一步:
class Widget{ //method called by the view render() {//output the markup based on the widget Type and interleaved the processed data} //methods called by the controller: public function __construct() {//recieve arguments for widget type (query and renderer), call create()} public function create() {//tell the widget to build the query, execute it, and filter the data} public function process_data() {//transform into JSON, an html entity etc} //methods called by the model: public function build_query() {...}; public function execute_query() {...}; public function filter_data() {...}; }看着它,我已经可以看到一些问题。
-
例如,将在控制器中创建的小部件传递给视图进行渲染是很简单的。
但在实施模型时,它似乎并不那么简单。表网关模式比 ORM 更易于实现。但由于表网关模式对每个模型/表都有一个类,它似乎不符合要求。我可以为特定表创建一个模型,然后在其中实例化所需的任何其他模型。但这似乎不适合表网关模式,而是 ORM 模式。 表网关模式可以用多个表实现吗?有哪些选择?控制器创建小部件,小部件创建模型有意义吗?
-
出现的另一个问题是这种设计无法轻松创建小部件。 IE。假设我想创建一个 PiechartWidget,可以重用多少代码?使用一些面向对象的想法,例如接口或抽象类/方法和继承,会不会更有意义?
假设我抽象了 Widget 类,因此只有共享方法被具体定义,其余的被声明为抽象方法。修改 Widget 类以使其抽象(第二遍):
abstract class Widget{ private $_type; private $_renderer; //methods called by the controller: //receive arguments for widget type (query and renderer), protected function __construct($type, $renderer) { $this->_type = $type; $this->_render = $renderer; $this->create(); } //tell the widget to build the query, execute it, and filter the data private function create() { $this->build_query(); $this->execute_query(); $this->filter_data(); } //methods called by the model: abstract protected function build_query(); protected function execute_query() { //common method } abstract protected function filter_data(); //method called by controller to tranform data for view //transform into JSON, an html entity etc abstract protected function process_data(); //method called by the view //output the markup based on the widget Type and interleave the processed data abstract protected function render(); }这是一个好的设计吗?如何改进?
我假设编写一个新的小部件至少需要一些新代码来构建查询,并且可能过滤数据,但它应该能够使用预先存在的代码来实现其几乎所有其余功能,包括已经存在的渲染器。
我希望任何人都可以对此设计提供至少一些反馈。验证它? 撕开它。叫我白痴。那也很好。我可以使用任何向前的牵引力。
几个具体问题:
第一季度。作为 Widget 类的一部分或作为单独的类,实现渲染器的最佳方式是什么? 1a。如果分开,它将如何与小部件类交互?
第二季度。我如何改进这种设计以简化新类型小部件的创建?
第三季度。最后,我觉得我在数据封装方面遗漏了一些东西。数据封装如何与需求相关并在此场景中发挥作用?
【问题讨论】:
-
这是使用 Zend 框架,所以 MVC 是固有的。
-
是否所有数据都像您给出的示例那样采用比率形式,或者某些小部件会显示比率而其他小部件会显示例如一组点?
-
您的问题是关于小部件还是包含小部件的页面?
-
只有一页就不需要 MVC。控制器执行导航部分,根据您的要求,您无需导航。
标签: model-view-controller design-patterns oop