我正在使用PHP应用程序,并且我希望能够实例化一个对象,但是我需要它才能仅使用它的一些属性进行实例化,而不是全部。例如
class User {
public function __construct() {
$this->user_id = 0;
$this->name = '';
$this->profile = array();
//...many other members here
}
}
每次我实例化这个对象时,它都会带来许多数据集合(例如,它带来了所有它的“profile”属性等等)。这有时不是想要的行为,因为,假设我只需要使用用户名,为什么要在内存中拥有所有其他属性?但在其他情况下,我会马上就需要它们。
一些想法:
我可以创建另一个扩展User的类,并在构造函数方法中取消设置任何不需要的属性。但是,我正在寻找一种更可重用的方法,所以我可以在我的应用程序中对其他一些对象做同样的事情。
我可以从构造函数方法中取出属性,但这可能会迫使我更改应用程序的核心(User类以上的类),并在应用程序中改变很多东西。
< / LI>是否有更可重用的方式,比如使用标准中间类或某些设计模式? 谢谢。
答案 0 :(得分:3)
实现它的一种方法是创建一个基类,它包含尽可能少的专业化以使其工作。扩展基类并根据需要逐步添加属性/功能将允许您控制添加的内容。
这符合普遍接受的面向对象设计模式。
答案 1 :(得分:3)
您要查找的关键字是急切加载与延迟加载。
简而言之:
-
两者的(非常基本的)实现看起来像下面的例子。
//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';
}