PHP类/ OOP:什么时候“引用”类中的类与扩展类?
当是理想的:PHP类/ OOP:什么时候“引用”类中的类与扩展类?
class USER {
// stuff about user
}
class PROFILE extends USER {
// stuff about user's profile
}
,当是理想的:
class USER {
$id;
$profile;
function __construct($id) {
$this->id = $id;
$this->profile = new PROFILE($id);
// set profile variables
}
}
class PROFILE {
$id;
// other variables pertaining to profile
function __construct($id) {
$this->id = $id;
}
}
我觉得更舒适的第二个例子吗?有什么特别的警告我应该知道吗?
我是否应该将其中一个视为不是互斥子集而另一个是儿童?
这是encapsulation和inheritance的经典问题。
使用封装:
- 当你想提供的基类的功能一些,但想隐藏一些。
- 当你想扩展/修改基类的功能,但不需要它是类型兼容的。
使用继承:
- 当你需要派生类是类型兼容的基类。换句话说,如果客户端代码需要引用
Derived
和Base
引用的实例。
在您的示例中,PROFILE从USER派生出来没有意义。用户具有配置文件,但配置文件不是用户。对于这个例子,USER类包含一个PROFILE字段是有意义的。
我会说,真正的方式做这将是:
class User {
private $id,
$profile;
public function __construct($id, Profile $profile) {
$this->id = $id;
$this->profile = $profile;
}
}
class Profile { ... }
new User(42, new Profile(...));
你不想来扩展类,除非有清晰的层次结构(Admin extends User
)。
你也不应该夫妇类似你在User
构造函数中所做的那样,而是使用如上所示的依赖注入。
所以如果我想创建一个用户,但不想创建一个配置文件,我可以在USER构造函数中只有Profile $ profile = NULL作为默认值?如果我想要手动注入它?我确实看到你关于耦合类的观点,以及为什么它不起作用,但是我会创建一个概要文件对象而没有将它与用户关联起来。或者更确切地说,有些时候我不想访问用户的个人资料,只是有关用户的基本信息,如ID和密码。 – xistva 2012-01-07 01:50:37
那么,在你的例子中,每个用户默认都有一个配置文件,而且你甚至不能控制该配置文件是什么,因为它是在用户的构造函数中默认构造的。这是一回事,真的。但通过将配置文件注入用户的构造函数,您可以更好地控制该配置文件的内容。您可以为不同种类的配置文件子类/扩展'Profile'类。你可以模拟它进行单元测试。如果您的业务规则是每个用户都必须拥有一个配置文件,那么在构造函数中需要一个配置文件。如果它可以是可选的,可以通过'Profile $ profile = null'来选择它。 – deceze 2012-01-07 03:20:08
通常,除非可以说PROFILE
只是一种特殊的USER
,并且在所有情况下都可以像USER
一样对待,您不希望使用继承来建模关系。一个USER
可能有一个PROFILE
或PROFILE
可能与特定USER
相关,但两者是不同的概念 - 所以没有一个应该从其他继承。
通常,父类更像是您将要扩展且很少自己使用的泛型类。所以继承更像它应该是这样的:你扩展一个泛型类。
我不会再去了动物的比喻,但这样的:
class USER {} // generic class
class ADMIN extends USER {} // specific class
class MOD extends USER {} // specific class
具有逻辑,因为我们扩展了一般的用户类指定类每种类型的用户。
对于任何不分层次的东西,我会使用封装。
我可以假设封装对扩展一个类来处理新协议有好处吗?如果让USER类扩展包含数据库连接函数的数据库类是否有意义? – xistva 2012-01-07 01:41:46
当然,但类似的东西需要基类提供派生类将使用的某种通用功能。如果新类完全不同,但是你想像对待第一个协议处理类那样对待它,那么你想要定义一个接口或抽象基类,这两个协议都是从中派生的。 – 2012-01-07 01:43:47
我喜欢这个解释。对于那些OOP的新手来说,问问自己是否继承的类是“父类”。例如,“是用户的个人资料?”答案是否定的,所以它不扩展USER。相反,如果它与问题“有一个”相匹配,那么它可能是一个属性/属性。例如,USER“有一个”PROFILE。 – 2012-01-07 01:44:19