0

快速背景:我正在用 PHP 编程,我有一个域模型,它有一个单独的数据访问层(DAO 类),负责从数据库中获取数据并创建域类。

假设我有一个 DAO 类负责创建groupgroupList对象。您可以将群组想象为社交网络的一个组成部分;尽管对于这个问题,它们是什么并不重要。

我需要能够要求 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)创建许多专注的创作方法,例如:

  • 创建列表()
  • 创建类别列表(类别对象)
  • 创建用户列表(用户对象)
  • 创建标签列表(标签)
  • 创建流行列表()

或者

b)创建一个可以做所有事情的 BIG 方法: - createList ( searchString, orderBy, filterByCategoryObject=null, filterByUserObject=null )

我非常喜欢(a)的想法,因为我的 DAO 接口更简单,不太可能需要更改(例如:当我突然需要传递一个日期来比较时添加另一个参数)当你有搜索之类的东西时,困难就来了您希望能够与其他参数组合的关键字;例如:搜索类别列表、搜索热门列表、搜索标签列表等... (a) 是我开始使用的。

我对重构 (b) 进行了调情,但我可以看到我的方法变得非常大而且非常复杂,而且在构建 SQL 时有很多“if”和“select”来处理不同的情况,并且输入该方法的许多参数。但至少这一切都在一个地方。你可以把东西结合起来;例如:一个用户的组,用 blah 标记,匹配关键字 blah。

4

5 回答 5

1

您可以创建一个所有公共方法都调用的私有方法。IE

private function _createList ( searchString, orderBy, ... )
{
    ...
}

public function createList()
{
    return $this->_createList('...', 'id');
}

public function createCategoryList()
{
    return $this->_createList('...', 'category_id');
}

这样,如果您的 _createList 函数稍后需要更改,您只需重构此 DAO 中的公共方法,而不是使用此 DAO 的所有类。

于 2009-09-10T07:49:52.307 回答
1

我不认为这是严格意义上的非此即彼的情况。选项 a 是您的 DAO 公开的一个很好的可用接口,所以我认为您应该保留它。对我来说,选项 b 确实看起来像是实现特定的逻辑。因此,如果 BIG 方法适合您的目的,我会说使用它来执行实际的处理逻辑,同时像选项 a 那样公开接口。

也就是说,如果 BIG 方法变得过于复杂和复杂并且代码重用实际上增加了代码复杂性并降低了应用程序的可维护性,那么您可能需要重构以为每个接口方法保留单独的 SQL 语句,但让辅助方法执行公共逻辑解析结果。

于 2009-09-10T07:54:24.463 回答
1

选项 B 中的big方法几乎可以保证减少代码重用,并增加复杂性和维护时间。

就个人而言,(并且根据 Code Complete)方法应该做一件事并做好,而不是试图把所有东西都塞进去。避免将来不得不重构,并在第一次时聪明地做到这一点。

于 2009-09-10T08:30:20.900 回答
0

编程基础:将代码分解为部分或函数是一种很好的做法。

我会选择(a)选项;您将需要维护和调试代码。当你确实有一个错误时,你会很高兴你将代码拆分为各种方法。

另外,写下方法名可以帮助你理解你在做什么。

比较一下:

选项(一)

$obj->AddNewList( /* params */ );
$obj->UpdateList( /* params */ );

还有这个:

选项 (b)

$obj->parse( /* first set of params */ );
$obj->parse( /* second set of params */ );

当人类从左到右阅读时,它可以节省时间。这就是为什么函数和方法名称总是在左边。

于 2009-09-10T07:28:59.277 回答
0

如果任一性能不是主要问题,或者组变化足够慢以使查询缓存变得有用,您可以编写过滤函数并将其传递。如果您正在遍历组并且有一个可选的过滤方法数组,那么您的循环会成为:

for(group in group) {
    cont = true
    for(f in functions) {
        if ! f(group) {cont = false; continue;}
    }
    if(cont) Continue
    add group to list
}

这将允许您在不更改循环的情况下更改过滤参数,只需编写或更改函数。

于 2009-09-10T07:34:08.943 回答