编辑:为了消除一些困惑,我实际上并没有使用Male
和Female
。一个更好的例子是父类Animal
和子类Cat
和Dog
。
我对OOP不熟悉,但到目前为止我已经很好地掌握了它。但是,有一点我可以找到一种方法。
首先,我创建了一个基于用户创建一个新对象。用户可以是(例如)男性或女性,但我无法检查他们是否没有检查数据库。然后我需要用他们性别的子类创建一个新的用户对象
例如,这是我当前(杂乱的)代码:
$user = new Person();
$userType = $user->GetUserType($userid);
if ($userType == 'Male') {
$user = new Male($userid);
} else {
$user = new Female($userid);
}
如果我想制作一个新物品,我必须每次都这样做,这是我不想要做的事情。
这里有一些代码可以帮助我们更好地理解这一点:
class Person {
function GetUserType($userid) {
$db = mysqlConnect();
$stmt = $db->stmt_init();
// Get the players information
$stmt->prepare("SELECT user_type FROM user_information WHERE user_id = ?");
$stmt->bind_param('i', $userid);
$stmt->execute();
$stmt->bind_result($userType);
$stmt->fetch();
$stmt->close();
$db->close();
return $userType;
}
}
class Male extends Person {
// Male based things here
}
class Female extends Person {
// Female based things here
}
因此,在__construct
课程的Person
中,我希望检查用户的性别并设置相应的子课程。
答案 0 :(得分:2)
因此,在Person类的
__construct
中,我希望检查用户性别并设置相应的子类。
就像其他地方已经说过的那样,ctors不会回来,所以你不能这样做。并且ctors不应该查询数据库,因为that would be doing work。如果您不能/不希望通过DataMapper或Repository立即创建正确的子类型,则可以使用State Pattern:
允许对象在其内部状态更改时更改其行为。该对象似乎会改变其类。
这是Behavioral Patterns中的Gang Of Four book之一。显然,关键字就是这里的行为。状态模式不是关于变化的子类型(Cat,Dog),而是关于它们具有的行为的差异。因此我对你的问题发表评论。
interface GenderBehavior
{
public function someBehavior();
// can add more methods here
}
class FemalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// female specific behavior
}
}
class MalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// male specific behavior
}
}
class UnknownGenderBehavior implements GenderBehavior
{
public function someBehavior()
{
// either implement a neutral behavior or
throw new LogicException('Unknown Gender set');
}
}
要创建这些实例,请添加Factory
class GenderBehaviorFactory
{
public static function create($sex = null)
{
switch ($sex) {
case 'male':
return new MalePersonBehavior;
case 'female':
return new FemalePersonBehavior;
default:
return UnknownGenderBehavior;
}
}
}
然后将GenderBehavior
接口添加到Person
类,并将对接口方法的所有访问权限传递给Behavior实例:
class Person implements GenderBehavior
{
private $behavior;
public function __construct()
{
$this->behavior = GenderBehaviorFactory::create();
}
public function changeGender($sex)
{
$this->behavior = GenderBehaviorFactory::create($sex);
}
public function someBehavior()
{
$this->behavior->someBehavior();
}
}
现在,当您第一次创建Person时,它将使用UnknownGenderBehavior
进行实例化,如果您尝试调用someBehavior
,则会引发异常。当您使用男性或女性作为参数调用changeGender
时,将创建相应的GenderBehavior
并将其设置为Person
。然后你可以拨打someBehavior
。
答案 1 :(得分:0)
您无法选择从构造函数返回的内容,但您可以按原样采用层次结构(Person
属于未知性别,Male
和Female
已知)并使用类似的内容这种模式:
public class Person {
public function ensureHasGender() {
if ($this instanceof Male || $this instanceof Female) {
return $this;
}
// now construct a Male or Female object from $this and return it
$userType = $user->GetUserType($this->userid);
return new $userType($this->userid);
}
}
因此,您现在可以根据需要多次调用$user->ensureHasGender()
,并且只会在第一次构建特定于性别的实例。
但是,我认为这个策略值得怀疑。分开Male
和Female
课程可以获得什么?如果他们的行为如此不同,那么这可能是合理的,但这听起来不太可能。也许在延迟加载和适当条件的类中内部处理问题会更好。