我希望尽可能地改进我的OOP代码设计,但我坚持这个问题。
例如,我想在社交网站中获取用户的所有朋友的个人资料。所以我有表Friendships
和Profiles
。我有课程Friends
和Profile
。
让Friends
成为处理用户友谊的类,Friends::getFriendsProfiles()
是获取并返回所有用户朋友个人资料的函数。
所以在我的函数Friends::getFriendsProfiles()
里面,我可以做一个
表连接
(例如SELECT * FROM Friends LEFT JOIN Profiles ON Friends.user2 = Profile.userId WHERE Friends.user1 = :userid
)或
我可以只获取朋友的用户ID,为每个朋友ID创建一个Profile
对象,然后调用运行查询($profile->getProfile($friendid)
)的SELECT * FROM Profiles WHERE userId = $friendid
来获取朋友的个人资料。然后返回所有朋友的Profile
对象的集合。
选项1缺点:我的友谊课了解个人资料。当我需要对返回配置文件的方式进行更改时(例如,我想为每个配置文件对象添加另一个属性),我需要在两个不同的位置更改它。
选项2缺点:而不是进行1次查询(我认为应该在O(1)中运行?),现在是O(n),其中n是用户朋友的号码。
但是选项2更清晰,松散耦合。我应该选择哪个选项?
答案 0 :(得分:1)
选项1缺点:我的友谊课了解个人资料。和 当我需要改变一个简档的方式(例如我 想要为每个配置文件对象添加另一个属性),我需要更改 它分布在两个不同的地方。
域对象自然会有一些耦合。这只是您正在建模的系统的现实。这不是友谊和概况之间的耦合问题,而是业务层与数据层之间紧密耦合的问题。如果你有一个datamapper,finder类等,并且你的业务对象持久性无知,那么这样的改变应该不会太重要。
如果您使用第二个选项,则会遇到n+1 select problem。在这种情况下,当有更多重要的区域可以考虑去耦时,我不会牺牲性能。
答案 1 :(得分:1)
我肯定会使用选项1并且只使用1个查询。
如果构造函数可以使用数组,那么Friends
类对Profiles
一定不太了解。
你可以这样做:
SELECT Profiles.*
FROM Friends
LEFT JOIN Profiles ON Friends.user2 = Profile.userId
WHERE Friends.user1 = :userid
然后在循环中:
$profiles = array()
while ($data = mysqli_fetch_assoc($result)){
$profiles[] = new Profile($data);
}
一个可能更干净的解决方案是使其成为Profile
类的方法。
Profile::getFriendsProfiles()
循环:
$profiles = array()
while ($data = mysqli_fetch_assoc($result)){
$profiles[] = new self($data);
}
Profile
的构造函数可以是:
function __constructor(array $data = null)
{
if (null !== $data) {
// fill properties
$this->id_profile = $data['id_profile']; // example
...
}
}
如果SQL代码在Table Data Gateway
的另一个对象中会更好。
如果你真的不想改进你的OOP,那么请阅读有关软件设计模式的内容。
您可以从Martin Fowlers的网站here开始。