Php SOLID-单一责任原则是否适用于类中的方法?
我不确定我班上的这种方法是否违反了单一责任原则Php SOLID-单一责任原则是否适用于类中的方法?,php,oop,solid-principles,single-responsibility-principle,Php,Oop,Solid Principles,Single Responsibility Principle,我不确定我班上的这种方法是否违反了单一责任原则 public function save(Note $note) { if (!_id($note->getid())) { $note->setid(idGenerate('note')); $q = $this->db->insert($this->table) ->field('id', $note->getid(
public function save(Note $note)
{
if (!_id($note->getid())) {
$note->setid(idGenerate('note'));
$q = $this->db->insert($this->table)
->field('id', $note->getid(), 'id');
} else {
$q = $this->db->update($this->table)
->where('AND', 'id', '=', $note->getid(), 'id');
}
$q->field('title', $note->getTitle())
->field('content', $note->getContent());
$this->db->execute($q);
return $note;
}
基本上,它在一个方法中执行两个任务,即插入或更新
我是否应该将分为两种方法,而不是遵循单一责任原则
但是SRP只适用于类,不是吗?它是否适用于类内的方法
SRP-
一个类应该只有一个职责(即只有一个
软件规范中的潜在变更应能够
影响类的规范)
编辑:
列出注释(包括许多不同类型的列表)、搜索注释等的另一种方法
public function getBy(array $params = array())
{
$q = $this->db->select($this->table . ' n')
->field('title')
->field('content')
->field('creator', 'creator', 'id')
->field('created_on')
->field('updated_on');
if (isset($params['id'])) {
if (!is_array($params['id'])) {
$params['id'] = array($params['id']);
}
$q->where('AND', 'id', 'IN', $params['id'], 'id');
}
if (isset($params['user_id'])) {
if (!is_array($params['user_id'])) {
$params['user_id'] = array($params['user_id']);
}
# Handling of type of list: created / received
if (isset($params['type']) && $params['type'] == 'received') {
$q
->join(
'inner',
$this->table_share_link . ' s',
's.target_id = n.id AND s.target_type = \'note\''
)
->join(
'inner',
$this->table_share_link_permission . ' p',
'p.share_id = s.share_id'
)
# Is it useful to know the permission assigned?
->field('p.permission')
# We don't want get back own created note
->where('AND', 'n.creator', 'NOT IN', $params['user_id'], 'uuid');
;
$identity_id = $params['user_id'];
# Handling of group sharing
if (isset($params['user_group_id']) /*&& count($params['user_group_id'])*/) {
if (!is_array($params['user_group_id'])) {
$params['user_group_id'] = array($params['user_group_uuid']);
}
$identity_id = array_merge($identity_id, $params['user_group_id']);
}
$q->where('AND', 'p.identity_id', 'IN', $identity_id, 'id');
} else {
$q->where('AND', 'n.creator', 'IN', $params['user_id'], 'id');
}
}
# If string search by title
if (isset($params['find']) && $params['find']) {
$q->where('AND', 'n.title', 'LIKE', '%' . $params['find'] . '%');
}
# Handling of sorting
if (isset($params['order'])) {
if ($params['order'] == 'title') {
$orderStr = 'n.title';
} else {
$orderStr = 'n.updated_on';
}
if ($params['order'] == 'title') {
$orderStr = 'n.title';
} else {
$orderStr = 'n.updated_on';
}
$q->orderBy($orderStr);
} else {
// Default sorting
$q->orderBy('n.updated_on DESC');
}
if (isset($params['limit'])) {
$q->limit($params['limit'], isset($params['offset']) ? $params['offset'] : 0);
}
$res = $this->db->execute($q);
$notes = array();
while ($row = $res->fetchRow()) {
$notes[$row->uuid] = $this->fromRow($row);
}
return $notes;
}
该方法将注释持久化到数据库中。如果这是它应该做的,那么这是一个单一的责任,实施是好的。您需要将决定是否插入或更新的逻辑放在某个地方,这似乎是一个很好的地方
只有当您需要在没有隐式决策逻辑的情况下显式地执行插入或更新时,才有必要将这两种方法分离为可以单独调用的不同方法。但目前,将它们保持在相同的方法中可以简化代码(因为后一半是共享的),因此这可能是最好的实现
免费范例:
public function save(Note $note) {
if (..) {
$this->insert($note);
} else {
$this->update($note);
}
}
public function insert(Note $note) {
..
}
public function update(Note $note) {
..
}
如果您有时出于任何原因需要显式地调用
insert
或update
,那么上述内容是有意义的。SRP并不是这种分离的真正原因。坚实的原则应用于类级术语,它们没有明确说明方法。SRP本身声明,类应该有一个更改的理由,所以只要您可以替换封装在一个类中的责任,就可以了
考虑这一点:
$userMapper = new Mapper\MySQL();
// or
$userMapper = new Mapper\Mongo();
// or
$userMapper = new Mapper\ArangoDb();
$userService = new UserService($userMapper);
所有这些映射器都实现一个接口并承担一项责任——它们为用户提供抽象存储访问。因此,映射器有一个更改的原因,因为您可以轻松地交换它们
您的案例通常与SRP无关。更多的是关于最佳实践。好的,关于方法的最佳实践表明,只要可能,它们应该只做一件事,并且接受尽可能少的参数。这使得阅读和查找bug更加容易
还有一个原则叫做。它只是说明方法名应该显式地执行其名称所暗示的操作
下面是您的代码示例:
save()。通过在那里执行插入和更新,您可以打破PoLA
就是这样,当您显式调用insert()
时,您知道并期望它会添加一条新记录。关于update()
method也一样-您知道并期望它会更新一个方法,但它不会创建一个新方法
因此,我不会在save()
中同时做这两件事。如果我想更新记录,我会调用update()
。如果我想创建一个记录,我会调用insert()
谢谢。我上面编辑的方法怎么样。例如,它用于同时列出注释和搜索注释。这样做可以吗?还是我应该把它们分开?那么它是否违反了SRP?好吧,该方法的职责是获取一系列搜索条件并返回注释列表。总是一样的。即使实现可能相当复杂,并且可能被重构为单独的清洁方法,也不会违反SRP。简而言之,SRP意味着您应该能够用一句简短的话描述方法/类/模块的功能。一旦你需要用这个来描述它,它会做foo,bar,baz,它还会煮咖啡,这可能违反了SRP。“接受参数X并返回结果Y”是一个责任。一个太多的例子是:“这个类管理数据库连接,序列化数据,呈现模板,缓存响应”。从“持久存储”的角度考虑这一点很有用。您可以在内存中创建一个Note
对象,并根据需要使用它,但一旦脚本结束,该对象就会消失。因为它并没有在任何地方持续存在。数据库(或任何其他存储机制)只是将对象持久化,以便您以后可以再次使用它。它只是意味着“保存到数据库”,但从概念上讲,它有助于区分“数据库是我的核心”和“数据库只保留我的对象数据”。关于这种思维方式的用处:您的getBy
方法目前正专注于构建一个巨大的SQL查询,该查询将返回您想要的确切数据,因此,这种方法相当复杂。然而,如果您从一个返回一个对象数组的方法的角度来考虑,那么这些对象是如何产生的并不重要。您可能可以将该方法分解为几个较小的查询,然后将结果组装到对象中,而不是要求SQL在一个结果中准确返回对象数据。我不同意save
仅意味着插入或更新save
对我来说相当于persist
,在这种情况下,我不关心底层实现做什么,只关心我下次请求时能够再次检索到该数据。@deceze您会如何评论save()
?当单独测试时,它是否仍然比两种方法更好(就预期和可读性而言)insert()
和update()
?对于这种操作,有一个非常常见的术语:upsert。我不知道是否有人对一个起义者的所作所为感到惊讶。我会站在你这边说,save
的当前实现不合理(取决于对象