2010-01-22 52 views
9

注意: 此问题已更新,以提供比以前更多的细节和洞察力。使用MVC,OO和设计模式的软件设计入门

更新: 我只想对所有回复的人表示感谢。对于Widget,哪种设计模式最适合,我仍然处于黑暗中。也许工厂或生成器模式之一?


我刚刚开始了一个新项目,需要使用MVC,OO和设计模式。

这里有个想法:设想一个显示一组小部件的页面。这些小部件(通常)是基于数据库中几个独立表中包含的数据的图表。我使用一个运行的页面示例来报告学生的表现。

高层次的需求

  • 显示一组(HTML仅)小部件的页面。
  • 小部件的数据将基于数据库查询。
  • 该页面可用于查看包含类似布局数据的单独数据集。例如,单个页面将显示报告单个学生表现的各个方面的小部件。
  • 想看另一个学生的表现,拉另外一页。不需要为不同的学生显示不同的小部件(尽管稍后可能会很好)。
  • 可能有很多学生,但数据库中包含的数据同样是为所有学生制定的。
  • 小部件显示的方式可以很容易地进行更改(比如将小部件从饼图显示为条形图显示)。
  • 小工具应该能够快速创建。

低级别要求

  • 目前的数据并没有改变,因此部件不会需要自动更新自己。
  • 小工具可能表示两件事的比例(例如,失败测试与成功测试的比例为饼图),一系列点或有时单个数值。
  • 新窗口小部件的开发应该轻而易举,现有的代码不需要修改。
  • 要使用的框架:基于MVC的Zend Framework。

定义窗口小部件有三件事情:要报告的数据集(在上面的示例中,学生ID),描述所报告的度量的查询以及渲染模式(条形图,时间序列等)。

这里是一个打破的责任MVC的每一层的一通:

查看: Zend的看法与PHP的HTML模板注入。它们将包含几种类型的小部件中的一种。小部件的各种形式,包括:静态JPEG图像(从远程站点即加载:<img src="http://widgetssite.com?x=2&y=3"/>,基于JSON JavaScript的窗口小部件,或各种(饼图,柱状图等)的图表

控制器:创建窗口小部件,将它们分配给视图之后,要在页面上显示的一组小部件需要保存在某处,因为我不能想到在视图中这样做的好方法,我将它添加到控制器中如果有更好的地方请留言,控制器还必须处理其他输入参数并将它们传递给小部件,例如,可以在url行传递的data_set id为http:/.../report/?student_id=42

模型:Zend Framework中的模型负责提取数据,因此很可能包含每个用于访问数据库的窗口小部件的类。

几点:

  1. 这里的模型,代表了一个特定插件的数据。因此,必须知道查询将会是什么,以便将获取数据所需的表拉到一起。

  2. 还有一个额外的处理步骤,在小部件可以呈现数据之前很有可能是必要的。这取决于将使用哪个渲染器。有时它可能需要从返回的数据中形成一个url。其他时候,一个JSON数组。其他时候可能会创建一些标记。这可以在模型或控制器或视图中进行。除非任何人可以想到将其移动到控制器或视图的充分理由,否则最好让它生活在模型中,并保持视图和控制器精简。

  3. 同样,一个小部件将由3件东西,它的参数,它的数据和它的渲染器组成。

    问题的一大部分是:在面向对象设计中表示小部件的好方法是什么?我已经问过这一次,无法得到答案。 是否有可应用于Widgets的设计模式,对于此项目最有意义?

    这里是在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() {...}; 
    } 
    

    看着它,我已经可以看到一些问题。

  4. 例如,将在控制器中创建的窗口小部件传递给视图以进行渲染很简单。

    但是,当涉及到实施模型,它似乎不是那么直截了当。表格网关模式比ORM更容易实现。但是,由于表格网关模式对于每个模型/表格都有一个类别,因此它似乎不适合该账单。我可以为特定的表创建模型,然后在其中实例化任何其他需要的模型。但这似乎不适合表格网关模式,而是适合ORM模式。 可以使用多个表来实现表格网关模式吗?还有什么替代方法?控制器创建窗口小部件并且窗口小部件创建模型是否有意义?

  5. 出现的另一个问题是,此设计无法轻松创建窗口小部件。即。假设我想创建一个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(); 
    } 
    

    这是一个好的设计?如何改进?

  6. 我认为编写一个新的小部件需要至少一些新的代码来构建查询,并可能过滤数据,但它应该能够使用预先存在的代码来处理其余所有功能,包括已经存在的渲染器。

我希望任何人都可以提供此设计的至少一些反馈。验证它? 撕开它。叫我白痴。这也没关系。我可以使用任何向前牵引。

一些具体问题:

Q1。作为Widget类的一部分或作为单独的类来实现渲染器的最佳方式是什么? 1A。如果是单独的,它将如何与widget类进行交互? Q2302。我怎样才能改进这个设计来简化新类型的小部件的创建?

Q3。最后,我觉得在数据封装方面我缺少一些东西。数据封装如何与需求相关并在这种情况下发挥作用?

+0

http://en.wikipedia.org/wiki/Presentation-abstraction-control – alex 2010-01-22 02:18:06

+0

这是使用Zend框架,所以MVC是固有的。 – hinghoo 2010-01-22 02:25:38

+0

所有的数据都会以你给出的例子的比例的形式出现,还是有些小部件会显示一个比例,而其他小部件会显示比如一组点? – mattjames 2010-01-22 02:27:41

回答

1

所有这些想法背后的目的--MVC,模式等 - 基本上都是一样的:每个类都应该做一件事情,并且应用程序中的每个不同责任都应该分成不同的层次。您的意见(页面和小工具)应该很薄,如果有任何决定,除了呈现从模型收集的数据外,几乎不做任何决定。模型应该在数据层中进行无意义的操作,也就是说他们不应该知道他们的数据源是否是特定类型的数据源。控制器也应该很薄,基本上作为视图和模型之间的路由层。控制器从用户那里接受输入并在模型上执行相关操作。这个概念的应用取决于你的目标环境 - 网络,富客户端等等。

模型的架构本身并不是微不足道的问题。你有许多可供选择的模式和许多框架,并选择正确的模式或框架 - 完全取决于你的域名的细节,我们在这里只有很少的一部分给你更具体的建议。可以这么说,建议您花费一些时间来了解一些特定技术栈(无论是Java,.NET等)的几个Object-Relational Mapping框架以及它们构建的respective patterns

也让你自己熟悉MVPMVC之间的区别 - Martin Fowler的工作在这里很重要。

至于设计模式,大多数标准GOF模式的应用可以很容易地进入以某种形式或另一种打法,并建议你花时间在Design Patterns或关于该主题的许多introductory texts之一。这里没有人能够就MVC如何适用于您的域名给出具体的答案 - 只有经验丰富的工程师与产品负责人合作才能回答这个问题,该产品负责人有权制定工作流程和用户界面决策,从而大大影响这些决策的细节。

简而言之,您的问题的本质表明您需要一位经验丰富的OOP架构师或之前完成此工作的高级开发人员。或者在继续深入研究之前给自己留出大量时间。您的项目范围涵盖了许多编程人员需要数年才能完全掌握的大量学习内容。这并不是说你的项目注定要失败 - 事实上,如果你选择了正确的技术堆栈,框架等,并且假设你相当聪明并专注于手头的任务,那么你可能会完成很多工作。但是,获得像“MVC”或“OO”这样广泛的概念并不是我认为可以在第一次尝试和时间限制下完成的事情。

编辑:我刚刚发现你的编辑:Zend。有一个框架是很好的,这需要处理很多架构决策。我不熟悉Zend,但我会坚持默认设置。更多的依赖于您的最终UI交付 - 您是否处于RIA环境(如Flash或Silverlight)中,还是您处于严格的HTML/JavaScript环境中?在任何一种情况下,控制器都应该很薄,并且可以像路由器一样从HTTP获取和发布请求中获取用户请求,并立即切换到模型。意见也应该保持精简,尽可能少做出决定。在Web环境中应用的MVC的概念已经由Rails和随后的框架很好地确立,并且我假设Zend在这方面与CakePHP类似:应用程序服务器有一个路由系统,它将HTTP调用映射到控制器操作,以特定视图响应。请求/响应循环基本上是这样的:

  1. 用户请求通过URL张贴
  2. 路由器控制交给控制器类
  3. 控制器使得与给定PARAMS
  4. 的模型的模型的呼叫操作的数据,回发到控制器
  5. 框架完成的数据映射到一个视图,以某种代码隐藏的是把请求的结果在视图的范围。
  6. 该框架创建html(或xml或其他)并回发给调用者。
+0

终极UI交付==严格的HTML/JavaScript环境。 – hinghoo 2010-01-23 01:07:25

1

您可以考虑使用Subject Observer Pattern

有你的类,命名为DataReader的单一的主题。您的多个小部件将充当观察者。一旦你的DataReader从服务器接收到数据,它(Subject)会通知多个小部件(Observer)。

您的各个小部件可能会有不同的演示文稿,以呈现来自DataReader的同一组数据。

更新

在消息,其中主题通知观察者,您可以包括消息类型信息以及。小部件只会处理消息类型,这符合他们自己的兴趣,并忽略消息的其余部分。

+0

感谢您的回答。我很好奇它是否适用于小部件可能基于单独查询的情况。 另外,关于我的问题的第二部分,如何最好地将它集成到MVC设计中? – hinghoo 2010-01-22 02:27:37

+0

查看我的更新;) – 2010-01-22 07:19:07

4

#2,如果你是在Windows上使用WPF,或Silverlight在一般情况下,可以考虑使用MVVM模式(模型 - 视图 - 视图模型),这里是解释了WPF实现: MVVM at msdn

#1 (注释不是答案):对于MVC的确切实现(以及小的变体),它确实取决于你使用的是什么语言。

另一种替代MVC是MVP Model View Presenter

记住OO的目标不是硬塞设计模式到你的代码,但以更少的错误/增加可读性创建维护的代码。

1

这听起来像你想使用MVC和其他模式,因为它们是新的流行语。在模型视图和控制器之间拆分您的设计应该告诉您如何传播应用程序的功能。尽管我完全同意使用MVC是正确的方法,但我建议你研究一下模式并查看实现它的一些源代码。不过,作为您的问题的开始,将显示的小部件将成为您的观点,这应该是显而易见的。来自用户的输入(例如更改某个小部件的参数或请求其他信息)将进入您的应用程序并由控制器处理。一个具体的例子是一个基于Java的HttpServlet。控制器servlet接收用户请求,并要求应用程序的较低层(服务,持久性等)更新模型的表示形式。该模型包含所有特定于域的对象(即来自数据库的数据等)。这些数据(更新后的模型)返回到控制器,从而为用户推出新的视图。希望这足以让你开始设计你的应用程序。

作为进一步的帮助,您可以考虑使用框架来协助开发您的应用程序。我非常喜欢Spring,它有一个第一类MVC实现,它的确有助于指导您设计正确的MVC Web应用程序。

+0

可随时对投票人发表评论 – 2010-01-22 06:57:48

2

高要求 - 显示一组小部件的页面。小部件基于数据库中几个独立表中包含的数据。 - 小部件的数据将基于数据库查询。小部件以特定方式显示其数据。 - 小部件应该能够快速创建。

低级别要求 - 数据的变化,多个图表需要改变,推模型(从数据到UI) - 的新部件开发应该是一件轻而易举的事,现有的代码无需修改

从设计咨询模式基础 - MVC支持一对多的通知模式,所以是的,一旦你的小部件被初始化,创建并连接到网页,它应该等待来自数据库的通知。 - 战略模式,你的整个代码应该发展到一个界面。新的小部件应该被添加到参数化的LinkedList(或其他一些数据结构)中。这样,新的小部件开发人员只需实现接口,并且您的框架可以在不更改现有代码的情况下获取这些通知。

Siddharth

+0

我喜欢你的细分要求。我很抱歉没有更清楚。一个要求是关键的,它不是一个推式模型。小部件不需要频繁更新_that_。让我知道,如果你有一个建议使用什么模式的小部件的基础上。 – hinghoo 2010-01-23 01:13:39

0

注意:这是我基于新的更新问题的新答案。

这是一个建议的类图。我将在一个序列图上工作。 alt text

我以前的答案就在这里:

根据你所描述的要求,你的模型是您的数据库或数据仓库和你的看法是你的饼图,条形图等我没有看到控制器的需要,因为它听起来像你有一个带有小部件的单页仪表板。
您需要花时间在数据库模型上。由于您正在执行所有选择并且没有更新,因此请使用可使这些查询有效的非标准化数据模型。您应该将这些查询的结果放入基于维度数量的表类型对象(例如2维数组)或3维数组中。除非您使用动画,否则您仅限于3个维度。

+0

针对只选择系统的非规范化模式的好建议!请澄清你最后一部分“你应该推动...”的意思。这是为了缓存吗?还是为了最后的表示? – hinghoo 2010-01-23 01:15:50

+0

LWoodyiii:谢谢,你用什么来创建该图? – hinghoo 2010-01-25 00:22:41