OOP DAO 设计问题
Posted
技术标签:
【中文标题】OOP DAO 设计问题【英文标题】:OOP DAO design question 【发布时间】:2010-11-27 02:07:10 【问题描述】:快速背景:我正在使用 php 进行编程,我有一个域模型,它带有一个单独的数据访问层(DAO 类),负责从数据库中获取数据并创建域类。
假设我有一个 DAO 类负责创建 group 和 groupList 对象。您可以将群组想象为社交网络的一个组成部分;尽管对于这个问题,它们是什么并不重要。
我需要能够要求 DAO 根据各种不同的标准为我制作各种 groupList 对象:
最近添加的组 最受欢迎的团体 管理员将群组标识为“精选” 带有特定标签的群组 与某个关键字匹配的组 特定类别中的组 某个人创建的群组 在某一天创建的群组其中一些我现在实际上并不需要,但我可以想象在项目完成之前我会需要它们。现在我开始使用一个不错的简单 DAO 方法:createList。这很好用。您可以将伪代码视为:
find out how many groups
create SQL query to fetch group details
loop through results
create group object
add to group list object
随着我的应用程序的进展,我随后创建了一个新方法 createFeaturedList。这很好用。但它实际上与 createList 非常相似,只是查询略有不同。其余约 150 行代码中的许多代码都是相同的。
所以... 对于我需要的所有略有不同的情况,我应该怎么做? 大多数时候,我真的只是想根据某些标准对列表进行过滤和排序。问题是——我应该:
a) 创造许多专注的创作方法,例如:
createList() createCategoryList(categoryObject) createUsersList (userObject) createTagList(标签) createPopularList ()或
b) 创建一个可以做所有事情的 BIG 方法: - createList (searchString, orderBy, filterByCategoryObject=null, filterByUserObject=null)
我非常喜欢 (a) 的想法,因为我的 DAO 接口更简单,不太可能需要更改(例如:当我突然需要传入一个 date 进行比较时添加另一个参数) 当您有诸如搜索关键字之类的东西希望能够与其他参数结合时,困难就来了;例如:搜索类别列表、搜索热门列表、搜索标签列表等... (a) 是我开始使用的。
我对重构 (b) 有过兴趣,但我可以看到我的方法很快变得非常庞大和复杂,在构建SQL,以及许多输入该方法的参数。但至少这一切都在一个地方。你可以把东西结合起来;例如:一个用户的组,用 blah 标记,匹配关键字 blah。
【问题讨论】:
【参考方案1】:您可以创建一个所有公共方法都调用的私有方法。浏览器
private function _createList ( searchString, orderBy, ... )
...
public function createList()
return $this->_createList('...', 'id');
public function createCategoryList()
return $this->_createList('...', 'category_id');
这样,如果您的 _createList 函数稍后需要更改,您只需重构此 DAO 中的公共方法,而不是重构使用此 DAO 的所有类。
【讨论】:
大多数答案非常相似 - 我想相当明显!这个答案得到了很好的解释,所以我选择了它。感谢您的建议。【参考方案2】:我不认为这是严格意义上的非此即彼的情况。选项 a 是您的 DAO 公开的一个很好的可用接口,所以我认为您应该保留它。对我来说,选项 b 确实看起来像是实现特定的逻辑。因此,如果 BIG 方法适合您的目的,我会说使用它来执行实际的处理逻辑,同时像选项 a 那样公开接口。
也就是说,如果 BIG 方法变得过于复杂和复杂,并且代码重用实际上增加了代码复杂性并降低了应用程序的可维护性,那么您可能希望重构为每个接口方法保留单独的 SQL 语句,但让辅助方法执行解析结果的常用逻辑。
【讨论】:
【参考方案3】:选项 B 中的 big 方法几乎可以保证减少代码重用,并增加复杂性和维护时间。
就个人而言,(并且根据 Code Complete)方法应该只做一件事并做好,而不是试图把所有东西都塞进去。避免将来不得不重构,并在第一次时做到聪明。
【讨论】:
【参考方案4】:编程基础:将代码分解为部分或函数是一种很好的做法。
我会选择(a)选项;您将需要维护和调试代码。当你确实有一个错误时,你会很高兴你将代码拆分为各种方法。
另外,写下方法名可以帮助你理解你在做什么。
比较一下:
选项 (a)
$obj->AddNewList( /* params */ );
$obj->UpdateList( /* params */ );
还有这个:
选项 (b)
$obj->parse( /* first set of params */ );
$obj->parse( /* second set of params */ );
当人类从左到右阅读时,它可以节省时间。这就是为什么函数和方法名总是在左边。
【讨论】:
【参考方案5】:如果性能不是主要问题,或者组的变化足够慢以使查询缓存变得有用,您可以编写过滤函数并将其传递。如果您正在循环组并且有一个可选的过滤数组您的循环将成为的方法:
for(group in group)
cont = true
for(f in functions)
if ! f(group) cont = false; continue;
if(cont) Continue
add group to list
这将允许您在不更改循环的情况下更改过滤参数,只需编写或更改函数。
【讨论】:
我真的想专注于在创建组对象之前从数据库中获取我需要的信息——而不是仅仅创建所有对象然后过滤。可能有很多个对象。以上是关于OOP DAO 设计问题的主要内容,如果未能解决你的问题,请参考以下文章