仅使用其部分成员实例化对象

时间:2013-08-07 20:25:57

标签: php object

我正在使用PHP应用程序,并且我希望能够实例化一个对象,但是我需要它才能仅使用它的一些属性进行实例化,而不是全部。例如

class User {

    public function __construct() {
        $this->user_id = 0;
        $this->name = '';
        $this->profile = array();
        //...many other members here
    }
}

每次我实例化这个对象时,它都会带来许多数据集合(例如,它带来了所有它的“profile”属性等等)。这有时不是想要的行为,因为,假设我只需要使用用户名,为什么要在内存中拥有所有其他属性?但在其他情况下,我会马上就需要它们。

一些想法:

  • 我可以创建另一个扩展User的类,并在构造函数方法中取消设置任何不需要的属性。但是,我正在寻找一种更可重用的方法,所以我可以在我的应用程序中对其他一些对象做同样的事情。

  • 我可以从构造函数方法中取出属性,但这可能会迫使我更改应用程序的核心(User类以上的类),并在应用程序中改变很多东西。

    < / LI>

是否有更可重用的方式,比如使用标准中间类或某些设计模式? 谢谢。

3 个答案:

答案 0 :(得分:3)

实现它的一种方法是创建一个基类,它包含尽可能少的专业化以使其工作。扩展基类并根据需要逐步添加属性/功能将允许您控制添加的内容。

这符合普遍接受的面向对象设计模式。

答案 1 :(得分:3)

您要查找的关键字是急切加载延迟加载

简而言之:

  • Eager Loading就是你在片刻所做的事情:一旦创建了一个对象,你就会加载所有相关的对象和属性,无论需要多长时间。
  • 延迟加载是相反的:只有在需要时才会加载信息。 (片刻,它真的被访问)

-

两者的(非常基本的)实现看起来像下面的例子。

//Data Model
abstract class UserModel{
    protected $userData = null;
    protected $userPosts = null;

    protected function loadUserData(){
        //do whatever required and store in $result
        $this->userData = $result;
    }

    protected function loadUserPosts(){
        //do whatever required and store in $result
        $this->userPosts = $result;
    }

    public abstract function getUserData();
    public abstract function getUserPosts();
}

//Eager Loading
class EagerUserModel extends UserModel { 
   public function __construct() {
        $this->loadUserData()
        $this->loadUserPosts();
    }

    public function getUserData(){
      return $this->userData;
    }

    public function getUserPosts(){
      return $this->userPosts;
    }
}

//Lazy Loading
class LazyUserModel extends UserModel {    

   public function __construct() {
        //do nothing
    }

    public function getUserData(){
      if ($this->userData == null){
        $this->loadUserData();
      }

      return $this->userData;
    }

   public function getUserPosts(){
      if ($this->userPosts== null){
        $this->loadUserPosts();
      }

      return $this->userPosts;
    }
}

示例将允许两种方式。但是,如果您不想使用哪种类型的“选择”,您可以在单个类中实现预先加载或延迟加载。

Eager Loading具有以下优势:每条信息都“就在那里”。然而,延迟加载需要更复杂的架构。要加载“UserPosts”,您可能需要有关用户的其他数据,这意味着您必须先加载UserData。这是你需要考虑的事情!

那么,延迟加载总是更快?

没有!那是陷阱。想象一下,你有一个有10个属性的类。如果以惰性方式加载每个Attribute,则需要触发10个SQL查询(SELECT Name FROM user...SELECT email FROM user...等等)。以急切的方式执行此操作将允许您只运行一个查询:Select Name, email FROM user...

您必须在两种方法之间找到平衡点。异物是否紧密耦合? (即用户&lt; - &gt;组)? - &GT;加载渴望。外来物体是否松散耦合(用户 - >图像545458上的帖子) - &gt;加载懒惰。

另请注意,这是一个极端示例(100%渴望与100%懒惰)。在实践中,您可能希望加载一些渴望(用户数据,组分配)和其他懒惰(注释,组权限)的东西 - 您无法为每个用例创建自己的基类扩展。但是,拥有“BaseClass”总是一个好主意,因为只要需要其他实现,它就会给你灵活性。

答案 2 :(得分:0)

如果您正确编写了实体,我宁愿保留它,也不要担心一些空属性,如果实体保持其一致状态缺少某些值。如果您不需要它们,请不要使用它们。如果你的脚本更复杂或者运行时间很长,那么当你不再需要它们时,请注意破坏对象。

如果实体可以推广到更常见的实体,并且稍后可以用作其他实体的基类,并且有意义,那就这样吧。这将是更困难的方式,因为需要重构。

当用户实体仅保留主要用户数据时,您还可以使用对象组合,并且将为另一个名为profile的对象准备一个值,例如:

class User {

    public function __construct() {
        $this->user_id = 0;
        $this->name = '';
        $this->profile = null;
    }

    public function hasProfile()
    {
        return $this->profile != null;
    }
}

class Profile {

    public function __construct() {
        $this->profile_id = 0;
        $this->userPrefOne = '';
        //...other members here
    }
}

// then
$user = new User();

if ($profileDataNeeded)
{
    $user->profile = new Profile();
    $user->profile->userPrefOne = 'something';
}