我使用symfony框架在PHP中进行开发,但这个问题也更广泛地适用于非symfony和非PHP开发人员。(对于symfony开发人员,我使用单表继承映射将子类映射到使用Doctrine ORM的DB,BasePerson扩展了FOSUserBundle,然后进一步扩展了两个子类。)
"BasePerson"扩展了原来的User类,该类进一步扩展为两个独立的子类:摄影师和摄影对象。
有子类是一种很好的逻辑分离,然而,当我有一个摄影师也是摄影对象时,问题就出现了。他们共享相同的电子邮件地址,但用户名不同(在User类中)。
然而,现在我有两个对象用于同一个人(同一用户):一个PhotoSubject和一个Photographer,两者都有不同的用户名和潜在的不同密码等,这在Doctrine中显然是不可能的——它们需要存储为两个不同用户名的独立DB记录。对我来说,同一用户有两个不同的登录似乎是一个设计问题
有人能为这个问题提出正确的设计方案吗?我是否应该完全不使用继承来避免这个问题,而是使用一个没有扩展的单片"BasePerson"类。当用户登录时,我是否应该以某种方式在数据库中检查另一个具有相同电子邮件地址的"人"?或者这个问题还有其他解决方案吗?
我认为您混淆了继承、行为和数据。在这种特殊情况下,我宁愿用接口替换Photographer
和PhotoSubject
类
interface Photographer {
/**
* @param PhotoSubject[] $filter subjects to filter the photos
*
* @return Image[]
*/
public function getPhotos(array $filter);
public function addPhoto(Image $photo);
/** @return Image */
public function shot(PhotoSubject $subject);
// any other methods
}
interface PhotoSubject {
/**
* @return Image[] the images of the subject
*/
public function getSubjectShots();
}
class Person implements Photographer, PhotoSubject {
/** @var Image[]|ArrayCollection */
private $ownImages;
/** @var Image[]|ArrayCollection */
private $referencedShots =[];
public function getPhotos(array $filter) { return $this->ownImages->filter(...)->toArray(); }
public function addPhoto(Image $photo) {
$this->ownImages->add($photo);
$photo->setAuthor($this);
}
public function getSubjectShots() { return $this->referencedShots->toArray(); }
public function shot(PhotoSubject $subject) {
$image = new Image();
$this->addPhoto($image);
$image->addSubject($subject);
return $image;
}
}
您实际上不需要为世界上的每种类型的对象都有类。您只有一个对象—Person
,界面允许您从不同的角度显示Person
。在物理学中,它被称为"模型"——简单化的物体,描述当前所需的参数。这里也是一样,绑定到行为(接口),而不是实现。
我认为这里的问题是您混淆了关系和子类型。
摄影师可能是一种类型的人,只要它不会在未来的道路上给你带来类似的相互排斥的问题,但摄影对象不是一种类型。
照片主题应该是照片和人之间的关系(1照片->主题/人)