hin*_*hoo 9 oop model-view-controller design-patterns
注意:此问题已更新,以提供比以前更多的详细信息和见解.
更新:我只想对所有回复的人说声谢谢.对于Widget来说,哪种设计模式效果最好,我仍然处于黑暗中.也许是Factory或Builder模式之一?
我刚刚开始一个新项目,需要使用MVC,OO和设计模式.
这是一个想法:想象一个显示一组小部件的页面.这些小部件(通常)是基于数据库中几个单独表中包含的数据的图表.我使用一个报告学生表现的页面运行示例.
高级要求
低级要求
(最低限度)定义窗口小部件有三件事:要报告的数据集(在上面的示例中,学生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() {...};
}
Run Code Online (Sandbox Code Playgroud)
看着它,我已经看到了一些问题.
例如,可以直接将在控制器中创建的窗口小部件传递给要渲染的视图.
但是,当涉及到实施模型时,它似乎并不那么直截了当.表网关模式比ORM更容易实现.但由于表网关模式对于每个模型/表都有一个类,因此它似乎不符合要求.我可以为特定的表创建一个模型,然后在其中,实例化所需的任何其他模型.但这似乎不适合表格网关模式,而是适合ORM模式.表网关模式可以用多个表实现吗?有什么替代品?控制器是否创建窗口小部件并且窗口小部件创建模型是否有意义?
出现的另一个问题是这种设计无法轻松创建小部件.即.说我想创建一个PiechartWidget,可以重用多少代码?使用一些OO想法(如接口或抽象类/方法和继承)会更有意义吗?
假设我抽象了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();
}
Run Code Online (Sandbox Code Playgroud)
这是一个很好的设计吗?怎么可以改进?
我假设编写一个新的小部件将需要至少一些新的代码来构建查询,并且可能过滤数据,但它应该能够使用预先存在的代码来完成其余的所有功能,包括已经存在的渲染器.
我希望任何人都能提供至少一些有关此设计的反馈.验证它?撕裂它.叫我白痴.那也没关系.我可以使用任何前进牵引力.
一些具体问题:
Q1.实现渲染器的最佳方法是什么,作为Widget类的一部分或作为单独的类?1A.如果是单独的,它将如何与widget类进行交互?
Q2.我怎样才能改进这种设计以简化新类型小部件的创建?
Q3.最后,我觉得我在这里遗漏了一些有关数据封装的内容.数据封装如何与需求相关并在此场景中发挥作用?
所有这些想法(MVC、模式等)背后的目的本质上是相同的:每个类都应该做一件事,并且应用程序中的每个不同的职责都应该分为不同的层。您的视图(页面和小部件)应该很薄,除了呈现从模型收集的数据之外,几乎不会做出任何决定。模型应该不可知地在数据层上运行,也就是说,它们不应该知道其数据源是否是特定类型的数据源。控制器也应该很薄,基本上充当视图和模型之间的路由层。控制器接收用户的输入并对模型执行相关操作。此概念的应用因您的目标环境(Web、富客户端等)而异。
模型的架构本身就不是一个小问题。您有许多模式和许多框架可供选择,而选择正确的模式(模式或框架)将完全取决于您所在领域的具体情况,而我们这里的具体情况太少,无法为您提供更具体的建议。我只想说,建议您花一些时间了解一些适合您的特定技术堆栈(无论是 Java、.NET 等)的对象关系映射框架以及它们构建的相应模式。
还要让自己熟悉MVP和MVC之间的区别——Martin Fowler的工作在这里至关重要。
至于设计模式,大多数标准GOF模式的应用可以很容易地以某种形式发挥作用,建议您花时间阅读设计模式或有关该主题的许多介绍性文本之一。这里没有人能够给出关于 MVC 如何应用于您的领域的具体答案 - 这只能由经验丰富的工程师与产品负责人合作来回答,产品负责人有权做出工作流程和 UI 决策,这些决策将极大地影响其具体决策。
简而言之,您问题的本质表明您需要一位经验丰富的 OOP 架构师或以前做过此工作的高级开发人员。或者在继续前进之前给自己大量的时间进行深入研究。您的项目范围包含大量的学习内容,许多程序员需要数年时间才能完全掌握。这并不是说您的项目注定要失败——事实上,如果您选择正确的技术堆栈、框架等,并且假设您相当聪明并专注于手头的任务,您可能能够完成很多工作。但我认为,在时间有限的情况下,第一次尝试就无法获得像“MVC”或“OO”这样广泛的概念。
编辑:我刚刚听到你的编辑:Zend。拥有一个适当的框架是件好事,它可以处理很多架构决策。我不熟悉 Zend,但我会坚持使用它的默认值。这里更多取决于您的最终 UI 交付 - 您是否处于 Flash 或 Silverlight 之类的 RIA 环境中,还是处于严格的 HTML/JavaScript 环境中?在任何一种情况下,控制器仍然应该很薄,并作为路由器运行,从 HTTP 获取和发布中获取用户请求,并立即移交给模型。意见也应该保持薄弱,并做出尽可能少的决定。Rails 和随后的框架已经很好地确立了在 Web 环境中应用 MVC 的概念,我假设 Zend 在这方面类似于 CakePHP 之类的东西:应用程序服务器有一个路由系统,将 HTTP 调用映射到以特定视图响应的控制器操作。请求/响应周期基本上是这样的: