如何以正确的方式设计模型:面向对象或“包”为导向?

时间:2010-04-12 03:34:32

标签: php model-view-controller oop

我知道在OOP中你希望每个对象(来自一个类)都是一个“东西”,例如。用户,验证器等。

我了解MVC的基础知识,以及它们不同部分如何相互作用。

但是,我想知道MVC中的模型是否应该按照传统的OOP设计进行设计,也就是说,每个模型都应该是数据库/表/行(解决方案2)吗?

或者更倾向于收集影响同一个表或一堆相关表的方法(解决方案1)。

CodeIgniter中的地址簿模块的示例,其中我希望能够“CRUD”一个联系人并将其添加到一个可以接触CRUD的联系人组/从中删除。

模型解决方案1:将所有相关方法聚集在一起(不是真实对象,而是“包”)

class Contacts extends Model {

     function create_contact() {)
     function read_contact() {}
     function update_contact() {}
     function delete_contact() {}

     function add_contact_to_group() {}
     function delete_contact_from_group() {}

     function create_group() {}
     function read_group() {}
     function update_group() {}
     function delete_group() {}

}

模型解决方案2:OOP方式(每个文件一个类)

class Contact extends Model {
     private $name = '';
     private $id = '';

     function create_contact() {)
     function read_contact() {}
     function update_contact() {}
     function delete_contact() {}

}

class ContactGroup extends Model {
     private $name = '';
     private $id = '';

     function add_contact_to_group() {}
     function delete_contact_from_group() {}

     function create_group() {}
     function read_group() {}
     function update_group() {}
     function delete_group() {}

}

当我想创建模型时,我不知道如何思考。以上示例是我创建地址簿的真正任务。我应该把所有功能集中在一个类中。然后该类包含不同的逻辑(联系人和组),因此它不能保存特定于其中任何一个的属性。

解决方案2根据OOP工作。但我不知道为什么我应该这样划分。例如,有一个Contact对象会带来什么好处。它肯定不是User对象,那么为什么Contact应该“拥有”自己的状态(属性和方法)。因为我倾向于这样思考:如果某些东西需要一个状态,那么我创建一个OOP类,以便这些方法可以根据状态影响状态或其他事物。

模特也应该是“有状态的”吗?如果它们不需要状态,我为什么要根据OOP模式创建它。那么我可以像“包”解决方案一样将它们全部捆绑在一起。

你经历过OOP / MVC的人,请详细说明在这个非常具体的任务中应该如何思考(通常在创建模型时)

编辑:来考虑MVC中的控制器。它们是根据“包”解决方案创建的。这让我很奇怪......

3 个答案:

答案 0 :(得分:2)

我不知道是否有最佳方式,但我将分享我的方式......

我有一个表网关,例如ContactTableGateway,包含用于处理联系人的所有sql。我喜欢所有的sql都在一个地方。

class ContactTableGateway extends Model {

    function saveContact( Contact $contact )
    function getContact ( $contact_id )
    function createContact ( Contact $contact )

}

然后我有一个联系人类,基本上只有getter和setter(或公共属性)。此类的对象用作表网关的保存/创建

的参数
class Contact extends Model {

    function getName()
    function getAddress()
    function getEmail()
    ....

}

这是一个简化的例子

if ( isset( $_POST ) ) {

    // some validation here
    $contact = new Contact;
    $contact->name = $_POST['name'];
    $contact->email = $_POST['email']
    $contactTableGateway = new ContactTableGateway;

    if ( $contactTableGateway->createContact( $contact ) ) {
        echo "YAY";
    }
}

答案 1 :(得分:2)

  

每个模特应该是一个   数据库/表/行(解决方案2)?

没有。不要将模型的定义与其持久性方法联系起来。虽然对于简单的应用程序,您可以从数据库行对象扩展模型,但您应该至少在心理上将它们分开。

模型只是您域中实体的表示,因此必要时它们具有状态。在谈论Contact模型时,您实际上是在谈论映射器或网关,即从数据存储中检索模型的对象。令人遗憾的是,如此多的Active Record临时实施已经在这方面陷入困境。

Mappers可以作为静态函数的集合或作为对象实现 - 但是,如果您因任何原因(例如模拟单元测试)而需要扩展或更改行为,则集合的灵活性会降低。

模型本身应该只是一个数据集合,或者存储为公共属性,或者最好是适当的 setter和getter(请不要只为每个变量定义一个get / set函数对或者你不妨将它们公之于众,以及对数据进行操作的其他方法。它应该没有数据存储的概念或依赖于数据存储。映射器负责通过其接口实例化和初始化模型。这样做可以灵活地创建和保存模型。您可以从数据库,XML文件,代码内,通过网络发送的序列化流中执行此操作,无论您的船是什么漂浮,都可以通过替换不同的映射器,并且模型仍然完全不知道。

答案 2 :(得分:1)

我认为您的解决方案#2更优越,因为它更具分子/模块性,因此更容易理解,更灵活和可扩展(在OOP域中)。它也更加资源友好,因为它可以让你只需要在不需要联系人组功能时加载Contact类,反之亦然。这是分裂的好处。

如果模型不需要状态,那并不意味着OOP / MVC不适用。表模型可能在一个设计中没有状态,但这就是为什么我们有静态方法/成员,即Contact :: read($ id)。