我肯定会将该User
对象添加为File
类的属性,因为这是它背后的数据模型的实际表示。它还将使代码更加清晰,并将产生更简洁的File
对象使用代码。这也意味着File
如果设置了所有者 ID,则该类不必对有效性进行任何检查:如果传递了一个对象,它可以假定它是有效的(或者它不应该被构造)。
class File
{
protected $owner;
/**
* @var User $owner mandatory
*/
public function __construct(User $owner)
{
$this->setOwner($owner);
}
public function setOwner(User $owner)
{
return $this->owner;
}
public function getOwner()
{
return $this->owner;
}
}
现在很清楚,File
有一个强制属性owner
,即 a User
。
我还建议使用访问器而不是公共属性。这将是更多的未来证明,例如,如果您以后愿意这样做,它还允许您延迟加载用户。
class File
{
protected $ownerId;
protected $owner;
public function getOwner()
{
if (!$this->owner && $this->ownerId) {
$this->owner = User::getById($this->ownerId);
}
return $this->owner;
}
}
这意味着您的数据层会相应地填充对象,并且还需要一个经过调整的构造函数,并且会丢失自动类型检查(只有构造函数,仍然在 setter 中进行类型检查):
/**
* @var $owner int|User the user object or it's ID
*/
public function __construct($owner)
{
if (is_object($owner)) $this->setOwner($owner);
else $this->ownerId = $owner;
}
至于你的静态User::getById()
应该去哪里的问题:你应该将数据操作(对象的检索和持久化)分离在一个单独的层中。
class UserStore
{
public function getById($id)
{
// code to retrieve data from where ever, probably database
// or maybe check if the user was already instantiated and registered somewhere...
$user = new User($data['name'], $data['email']/*, ....*/);
return $user;
}
}
对于最后一个,我真的不建议构建自己的库(称为 ORM),存在许多出色的实现。看看Doctrine ORM。
最后,我想说减少班级规模本身不应该是一个目标。但是,您可以通过提取对象本身不固有的逻辑来降低其复杂性,就像 owner 属性一样。另一个示例可能是文件的路径:可能路径是相对存储的,并且您具有将其转换为绝对路径或获取扩展名或文件名的功能。此功能可以在单独的FileMeta
类中提取,或者您想要调用的任何内容,甚至可能是File
不同命名空间中的类:FileSystem\File
.