OOP (php) 在另一个 class 中实例化 class

OOP (php) instantiating class within another class

不确定我是否选择了正确的标题。但无论如何。

我必须支持和开发现有的项目。

它建立在 OOP 之上。

我有订单、产品等模型。它们经常用于代码中。

每个模型都绑定到相应的 table。

客户想要将一种新型客户集成到系统中。 这类客户拥有不同的关联数据,并订购完全不同种类的产品。所以订单看起来会有所不同。

我决定不把旧的秩序和新的秩序混在一起。起初我把它们放在不同的 tables 中,为了不破坏工作系统,并为它们创建了不同的 classes。

现在我有模型 Order.php 和 OrderNew.php、Product.php 和 ProductNew.php 等等。

我有全局设置 object,其中 属性 包含我需要实例化的 class 类型。

现在我已经搞砸了很多代码:

if ($global->object->isNewKindOfCustomer())  {
   $product = new ProductNew;   
} else {
   $product  = new Product;
}

但是在很多地方这样做我强烈地觉得我做错了很多事情。

所以我的第一个想法是应该由 class 产品决定什么产品应该被实例化。

如果我可以转到旧产品 class 并在其构造函数中执行以下操作,那就太完美了:

Class Product {
  __construct() {
    if ($global->object->isNewKindOfCustomer())  {
      $product = new ProductNew;   
    } else {
       $product  = new Product();
    }
  }
 }

此外,我将从 Product 继承 ProductNew 并重新定义所有需要更改的方法。类似于:

Class ProductNew extends Product {

  public methodsDefinedInProductButInNeedToBeChangedForProductNew (){
  }
}

但问题是我没能在 PHP 中找到一个合理的方法,而且它仍然闻起来不太好。但比第一种方法好得多(至少对我而言)。

第三个想法是,我现在将只创建 ProductNew class,还要创建 ProductOld class(不存在但我得到的本身)。

我会将所有代码从当前产品 class 移动到 ProductOld。 所以我当前的 Product class 将没有方法。它会变空。 此外,ProductNew 将从 ProductOld 继承。

有了这样的方案我根本不会去碰整个系统的代码。 在代码中的任何地方,assignemnts 都将具有以下外观

$product  = new Product

在内部,我需要以某种方式管理将在 Product 构造函数中创建的 object。

第四个想法是,我将首先创建一个通用的 class 并将其命名为例如产品通用。它将具有与 ProductNew 和 ProductOld classes 相关的方法。它们都将扩展 ProductGeneral。在 Product 内部,只有正确的 class 会根据当前用户的角色被实例化。虽然我不确定 ProductGeneral 是否有必要....

仍然不知道如何在产品 class 中替换它。我记得它在 C++ 中被称为类似动态绑定的东西。

有没有更好的解决方案来解决这个问题?我错过了什么吗?

对不起,文字太长了,我尽量让它尽可能短。

您可能想要一个具有所有基本功能的 Product class,一个具有特定功能的 ProductOld class,以及一个 ProductNew具有特定于 class 的功能。此外,ProductFactory 将 return 提供给您 class 您需要的产品。

在没有看到代码的情况下,很难说最好是按上面的方法做,还是只 extend Product class 和 ProductFactory.

哦不:(完全错误。

Class Product {
  __construct() {
    if ($global->object->isNewKindOfCustomer())  {
      $product = new ProductNew;   
    } else {
       $product  = new Product();
    }
  }
 }

你从哪里得到的$global?它不在您的构造函数中。您无法从任何地方获得实例。这会产生 untestable code.

您正在寻找 factory pattern

if ($global->object->isNewKindOfCustomer())  {
   $product = new ProductNew;   
} else {
   $product  = new Product;
}

But doing so in many places I got strong feeling that I do something very VERY wrong.

我同意。这就是覆盖的目的。
Assimung $global->objectCustomer 类型,添加一个方法 newProduct 可以根据需要重写:

class Customer
{
    public function newProduct()
    {
        return new Product();
    }
}

class CustomerNew extends Customer
{
    public function newProduct()
    {
        return new ProductNew();
    }
}

那么你必须检查一次你是在处理新的客户类型还是旧的客户类型(在实例化 CustomerCustomerNew 时),并且永远不会再检查一次。
这基本上就是 "factory pattern",只是不是单独的 class.

此外,我建议您不要使用 "normal" 旧的 class 和新的覆盖 class,而是将所有共同点移到新的基础 class , 喜欢

abstract class CustomerBase
{
    // Define here all methods that Customer and CustomerNew have in common

    // And make "implementation-dependent" methods abstract:
    public abstract function newProduct();
}

class Customer extends CustomerBase
{
    public function newProduct()
    {
        return new Product();
    }
}

class CustomerNew extends CustomerBase
{
    public function newProduct()
    {
        return new ProductNew();
    }
}

这将是一个 "cleaner" 实现(语义上),您仍然不必将代码中的每个 Customer 替换为 CustomerOld 或其他内容。
我建议你用 Product 做同样的事情,而不是仅仅覆盖 "default"

中的方法