【问题标题】:passing variables vs instances to constructor将变量与实例传递给构造函数
【发布时间】:2017-05-18 11:41:12
【问题描述】:

我有一个名为 Locations 的类,它应该接受 3 个参数名称、city_id、country_id。

传递这些值的最佳解决方案是什么,我应该传递变量或它们的类的实例。

$location = new Locations('Dubai, UAE', 1, 2);
$location = new Locations('Dubai, UAE', $cityId, $countryId);

我相信为了清晰和单一职责我应该使用依赖注入

$location = new Locations('Dubai, UAE', new City('Dubai'), new Country('UAE'));

何时以及为什么应该使用变量 (ID) 而不是实例?

【问题讨论】:

  • 或多或少是我的意见,但我觉得你应该只在将对象用于某些计算或操作时才传递对象,而不仅仅是存储它们。可能有人对消息来源有正确的答案。
  • 感谢@KevinSijbers
  • 这个问题的答案是见仁见智,因此在堆栈溢出方面是题外话。
  • 为什么类名是复数形式,因为它只代表一个位置?
  • @worldofjr 感谢您的输入,这是一个最佳实践/设计模式问题,我相信它与 stackoverflow 有一切关系,否则您将看不到人们的回答。无论如何,谢谢。

标签: php oop design-patterns solid-principles


【解决方案1】:

何时以及为什么应该使用变量 (ID) 而不是实例?

这是你的应用程序设计的问题,它可能在你所在的层上有很大的不同。

例如,为了操作数据库中的记录集,您可能只需要 id 值(非零,正整数)来对特定记录集执行操作。在这种情况下,您将需要 ID。

另一方面,位置可能甚至不需要 ID 来操作。

作为一个设计目标可能(应该)是,尽可能少地做,我想说你不要将 ID 值传递给 Location 构造函数,否则它会依赖在这些 id 来自的整个系统上(例如数据库)。这会将数据库层甚至数据库本身耦合到 Location 类。

但是 Location 类应该可以在完全不关心数据库的情况下工作。至少如果是这样,您可以更灵活地使用它,从而可以进一步发展。

这只是一些通用指针。它甚至可以更具体地实现,例如在创建类似于Flyweight Pattern 中概述的内容时。

因此,您最好询问并测试您的设计,确保它尽可能少地完成这项工作。

可能存在性能原因,例如,创建和传递整数值 (ID) 比实例化和传递对象值(对象)要快得多,但并非总是如此,甚至可以忽略不计。

根据您的问题和我的回答,我想澄清和评论一些事情:

  1. 变量既可以是 ID(值)也可以是实例。从技术上讲,PHP 中的对象变量就像一个 ID,它包含内存中实际对象的 ID(引用)。

  2. 您可以将构造函数视为实现细节。完成后,以后可以很容易地更改它,这样您就可以推迟细节。

  3. 我将它命名为 Location 类,因为它是单数的。班级名称应具有代表性,不得误导。 Locations 听起来像是零个或多个 Location 对象的集合。

  4. 这个问题无法完全回答,因为它取决于很多事情。为了更好地做出决定,还可以考虑the other answer,它显示了更多决策点。

【讨论】:

    【解决方案2】:

    我更喜欢第二个。

    使用 OOP 是在处理对象。通过传递对象,您可以传递的对象请求一些东西。

    如果你传递像整数这样的原语,它就没有上下文。传递的对象有自己的数据和逻辑,所以他自己知道最好的。 int 没有。

    在您的情况下,$cityIdCity 对象的裸数据:您不尊重City 对象,因为您传递了一个完全无上下文的值。

    【讨论】:

    • 它不是完全无上下文的,它自己的值会是,但是通过将它作为特定的方法参数传递,这为值提供了上下文。这种上下文不如拥有一个对象那么强大,至少在它不仅仅是一个值对象之前是这样。
    • 作为特定方法参数传递时,您会错过对该值的验证。谁应该验证?通过传递实例,这是一种非常有效的方式,因为该实例对他自己了如指掌;-) 其次,这听起来非常程序化。
    • 从技术上讲,我在学校里说你只传递有效的方法参数。所以要回答你的问题“谁应该验证”它是调用者。顺便说一句,对于 ID 来说没什么特别的,所以只是为了回答你的问题。你的意思可能是传递一个具体的类型而不是一个不那么多说的数字更舒服,我完全同意你。
    • 好的,调用者应该传递一个有效的实例/值。但如果没有,则有一个实例,有一个可用的上下文。没有价值。此外,传递值听起来不像 OOP。你真的很不喜欢使用接口类型的灵活性。
    【解决方案3】:

    PHP 的主要问题是,假设您的参数是 City 对象,您现在需要依赖应用程序的其余部分来正确执行此操作。您可以在构造函数中检查正确的类型,但这不会从函数头中立即显现出来。

    您正在以一种或另一种方式添加依赖项。问题是哪种形式的依赖最适合:

    1. 使用整数并在构造函数中构建 City 对象会导致实体类中的数据源(如数据库)存在依赖性,这可能会出现问题
    2. 保存整数并包含一个获取数据库对象的函数 getCity 会创建相同的依赖关系,但更易于管理,但这意味着您现在正在传递数据库对象。
    3. 传递 city 对象意味着它必须检查或假设参数的值,因为 PHP 使用动态类型,这会增加混淆要求,除非您有良好的文档,否则这可能会很烦人。
    4. 在 Location 中通过 city 并以任何方式对其进行更改会导致问题(如果事情变得复杂,您将来很难找到一些错误),这意味着您的对象应该是不可变的。
    5. 您的位置甚至需要城市吗?它是用于任何操作,还是只是用于显示?在我见过的许多情况下,实际用例中对象的唯一用途是检索传递的对象的 id,这可能更容易阅读,但如果对象不是不可变的,则效率低且容易出现问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-13
      • 2020-01-16
      • 2014-04-15
      • 2021-05-15
      • 1970-01-01
      • 1970-01-01
      • 2012-01-12
      相关资源
      最近更新 更多