实例化新对象或重用同一对象来存储数据


Instantiation of new object or reusing the same one for storing data

我有一个名为Customer的PHP类,函数为create(),它将客户的数据存储到数据库中:

class Customer
{
  public $createdby;
  public $cname;
  public function create()
  {
    ...
  }
}

由于我需要在一个只有名称($cname变量)更改的循环中存储更多的客户(为了简单起见,这里的$createdby变量对于该循环中所有创建的客户都是相同的,因为是同一用户创建了所有Customers),所以问题就来了——什么是(以及为什么)更好的做法;

方法A)重用相同的Customer对象,其中只更改已更改的属性:

$Customer=new Customer();
$Customer->createdby='somebody';
foreach($cnames as $cname)
{
  $Customer->cname=$cname;
  $Customer->create();
}

方法B)建立新的Customer对象并设置每个特定创建的所有属性,如:

foreach($cnames as $cname)
{
  $Customer=new Customer();
  $Customer->createdby='somebody';
  $Customer->cname=$cname;
  $Customer->create();
}

如果我想创建一个Customer对象数组,当然,我必须使用第二种方法。但事实并非如此。我看不出重用现有对象以将更多客户存储到数据库中的第一原则有任何缺点,但也许我错了。所以我问,以防万一,什么是更好的做法,为什么!

静态实例化器

首先,如果该方法是实例化方法,那么逻辑上是必me static(因为在实例化之前没有对象上下文)。实例化方法是静态方法的一个合法用例。因此,您的常规create()方法是错误的,因为它是在对象上下文上操作的。当然,您可以使用类__construct()魔术方法来实现这一点,以防您确信实例化逻辑始终相同。

使用工厂

另一种方法是使用一些工厂类来实例化具有给定数据的对象——因此,实现工厂模式。在你的情况下,这可能是:

class CustomerFactory
{
    public function createByNames($name, $createdBy)
    {
        $customer = new Customer();
        $customer->setName($name);
        $customer->setCreatedBy($createdBy);
        return $customer;
    }
}

这里的好处是,您的原始类可以摆脱实例化逻辑,工厂将负责根据业务规则&诚实正直例如,您可以在实例化中添加一些验证,并将某个验证器作为依赖项传递:

class CustomerFactory
{
    public function createByRawData(CustomerValidator $validator, array $customerData)
    {
        if(!$validator->check($customerData))
        {
            //or use some namespace, which I omit here to simplify case:
            throw new CustomerInstantiationException('Creation error '.$validator->getErrorMessage());
        }
        $customer = new Customer();
        $customer->setData($customerData);
        return $customer;
    }
}

正如您所看到的,这种方法更加灵活和可扩展,并且不需要修改Customer类,因为逻辑现在属于工厂。

集合实例化

在简单的情况下,您可以使用一个工厂来实例化多个对象。您可以返回这样的对象的数组,也可以添加类似于集合的特殊实体(其行为类似于集合,因此,很可能会扩展诸如Iterator之类的接口)。选择权在你——但我推荐第二种——而且,因为你将能够在不更改工厂代码的情况下扩展你的逻辑(只有你的收集行为,以后可以用一些东西来扩展)。

所以,你关于重复使用的问题的答案是——你需要决定是否需要不同的实例。如果是,并且目的是与多个实例交互,那么您应该分别创建它们。而且,如果它们的行为类似于某种集合,那么最好创建自定义集合类(它将实现Iterator或某些自定义集合接口),或者至少使用这样的对象数组。如果需要集合,那么我建议将实例化逻辑放在单独的工厂中,就像我上面描述的那样。

当您使用同一个对象时,很明显,您只有一个实体,它正在改变它的状态。如果这是你的逻辑的正确反映(也就是说:你真的只有一个客户),那么你可以使用它。但如果你的客户在逻辑上是不同的实体,那么这是错误的方法,因为在你重写同一个对象后,你将无法对他们进行操作。

对象是您的业务实体反射,它们的行为是业务逻辑反射

看起来两种方法是相等的,但我更喜欢第二种。它将使我摆脱一些潜在的问题,这些问题与create()方法的任何内部细节有关(例如,如果Customer对象不包含它,它可能会在某些beforeCreate()方法中生成一些唯一的哈希)。