【问题标题】:beginning OOP question about classes using classes开始关于使用类的类的 OOP 问题
【发布时间】:2011-07-16 05:54:45
【问题描述】:

我正在尝试用一组不错的类替换一个程序编写的网站作为学习练习。

到目前为止,我已经创建了一个记录类,它基本上在数据库的主表中保存了一行。

我还创建了一个loader 类,它可以:

loadAllFromUser($username)
loadAllFromDate($date)
loadAllFromGame($game)

这些方法从数据库中获取所有有效行,将每一行打包成一条记录,并将所有记录粘贴到一个数组中。

但如果我只想使用 一个 记录怎么办?我对此进行了尝试,最终得到的代码与我的原始程序几乎相同。

我也不确定那张唱片会去哪里。我的加载器类是否有受保护的记录属性?

我有点困惑。

编辑 - 另外,我将把用于向网站输出记录的 HTML 模板放在哪里?是放在记录类、加载器还是第三类?

【问题讨论】:

  • 所以你想分类返回一组结果,还是只返回一个特定的结果?
  • 我不知道我想让课程返回什么,这是我的问题。在网站上,有时您只需要一条特定的记录并显示所有详细信息,有时您可能需要 Bob 的所有记录的列表并仅列出日期、位置和 UID。

标签: php oop class


【解决方案1】:

我建议考虑使用 Doctrine 之类的东西来抽象您的 db-to-object 内容,而不是用于学习目的。

也就是说,有很多方法可以对这种类型的事物进行建模,但总的来说,处理它的库(无论是否自制)似乎倾向于在高水平上拥有:

  • 表示映射到 db 的对象的类
  • 一个类,表示该对象映射到 db 的方式
  • 表示从数据库中检索对象的方法的类

考虑需要完成的不同任务,并尝试将它们封装干净。记住The Law of Demeter 很有用,但现在不要太拘泥于试图深入了解面向对象设计理论中的所有内容——思考、设计、编码和查看哪里会更有用你设计的弱点在于你自己。

对于您的“使用一条记录,但不重复一堆代码”问题,可能类似于让您的 loadAllFromUser 方法实际上是调用私有方法的方法,该私有方法采用(例如)一个参数,即数字要检索的记录数,如果该参数为 null,则检索所有记录。

您可以更进一步,在您的 loader 类上实现 __call。假设它可以知道或找出您要加载的字段,您可以将参数构造为以编程方式执行加载的函数——查看函数的公共部分,看看有什么不同,看看是否可以找到一种方法将这些不同的部分变成函数参数,或者其他可以避免重复的方法。

MVC 值得一读您的第二个问题。至少,我可能希望将它放在一个单独的类中,期望通过一条记录来呈现。记录可能不应该关心它在 html 中的表示方式,为记录制作标记的东西不应该关心记录是如何获取的。一般来说,您可能希望尝试使事物尽可能独立。

这不是一件容易习惯的事情,而且在这种设计中“变得更好”大部分都是练习的问题。对于实际功能,测试可以提供很大帮助——假设您正在编写加载程序类,并且您知道如果您调用loadAllFromUser($me),您应该使用您的数据集获得一个包含三个特定记录的数组(即使它是使用的数据集仅用于测试),如果您可以运行一些可以在加载程序上调用它并检查正确结果的东西,它可以帮助您知道您的代码至少从行为的角度来看是正确的,如果不是从设计的角度来看——当您更改设计时,您可以确保它仍然正常运行。 PHPUnit 似乎是 php-land 中最流行的工具。

希望这会为您指明一组有用的方向,而不是仅仅让您感到困惑 :) 祝您好运,祝您好运。

【讨论】:

    【解决方案2】:

    您可以将loadAllFrom...loadOneFrom... 的独特部分封装在实用方法中:

    private function loadAll($tableName) {
        // fetch all records from tableName
    }
    
    private function loadOne($tableName) {
        // fetch one record from tableName
    }
    

    然后你就不会看到那么多重复了:

    public function loadAllFromUser() {
        return $this->loadAll("user");
    }
    
    public function loadOneFromUser() {
        return $this->loadOne("user");
    }
    

    如果你喜欢,你可以像这样进一步分解:

    private function load($tableName, $all = true) {
        // return all or one record from tableName
        // default is all
    }
    

    然后您可以将所有这些方法替换为以下调用:

    $allUsers = $loader->load("users");
    $date = $loader->load("date", false);
    

    【讨论】:

      【解决方案3】:

      您可以检查进入您的方法的参数并从那里做出决定。

          $args = func_get_args();
          if(count($args) > 1)
          {
              //do something
          }
          else // do something else
      

      一些简单的方法可以工作。或者您可以在您的类中创建两个单独的方法来处理每种类型的请求,就像@karim 的示例一样。哪个最适合您想做的事情。

      希望我能理解您的要求。

      回答您的编辑:

      通常你会想要创建一个视图类。这将负责处理数据的 HTML 输出。将这些分开是一个很好的做法。最好的方法是将您的“数据类”对象直接注入到视图类中,如下所示:

      class HTMLview
      {
          private $data;
      
          public function __construct(Loader $_data)
          {
              $this->data = $_data;
          }
      }
      

      既然这个类包含您处理的数据库信息,然后继续输出。

      【讨论】:

      • 根据传递给它的参数数量来改变方法的行为,会使你的 API 更难阅读。方法应该做一件事。
      【解决方案4】:

      如果您向它提供了一条识别信息(例如它的 ID),那么您的记录类可以附加一个知道如何加载单个记录的实用方法,这是完全有可能且合理的。

      我一直使用的模式是对象可以知道如何加载自己,并且还提供静态方法来执行“loadAll”操作,将这些对象的数组返回给调用代码。

      所以,我自己也通过自己开发的一个小型开源 Web 应用程序经历了很多这样的事情,我在程序的紧要关头中编写了大部分内容,因为这是我所知道的制作工作的方式(呵呵,是的)在最短的时间内完成应用程序 - 现在我将回顾并实施繁重的 OOP 和 MVC 架构。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-25
        • 2013-04-28
        • 2016-12-22
        • 1970-01-01
        • 2013-05-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多