决策逻辑是否更适合生活在作出决策的类中或单独的类中?

时间:2014-01-31 15:04:20

标签: design-patterns theory

采取简化的情况:我有一个类,它的工作是在给定路径上创建某些文件(让我们称之为FileCreator)。但是,只有在所述路径中尚不存在文件时才需要创建文件。

FileCreator检查文件是否存在于路径中然后创建它们是否更好,或者创建第二个负责检查的类(FileChecker)并让FileCreator完全进行创建(没有是否确实存在与否?)

情境1 :决策逻辑依赖于决策

class FileCreator
  def initialize(path)
    @path = path
  end

  def create_files
    unless files_exists?(path)
      #create files at path
    end
  end

  def files_exists?(path)
     #check if files exist at path
  end
end

file_creator = FileCreator.new('/foo')
file_creator.create_files

情境2 :决策逻辑位于自己的班级

class FileChecker
  def initialize(path)
    @path = path
  end

  def files_exists?(path)
     #check if files exist at path
  end
end

class FileCreator
  def initialize(path)
    @path = path
  end

  def create_files
    #create files at path
  end
end

file_checker = FileChecker.new('/foo')
file_creator = FileCreator.new('/foo')
file_creator.create_files unless file_checker.files_exists?

第一个场景更方便,但我想第二个场景更灵活(从某种意义上说,我现在确切地知道哪个类究竟是什么,所以我可以很容易地将它们放在一起)。

我对编程很陌生,所以对这个特定问题的想法或模式的任何外部引用都会受到赞赏(同样,不确定这个问题是否被正确标记)。

4 个答案:

答案 0 :(得分:3)

我会保持尽可能简单(但不简单; - )

在你刻意简化的例子中我会有一个单独的类,Check功能与Create功能密切相关,所以有一定程度的凝聚力,所以我们可以争辩说这段代码属于一个。 / p>

我有动力在某些条件下将代码重构为单独的类。在解释一些这样的条件之前,请注意思考过程:我知道我可以重构我是否需要,实际上我可以这样做而不会扰乱任何创建功能的用户;设计有一些内在的灵活性,我们只是考虑重新安排Create实现的内部。

将重构分为两类的一些可能原因:

  1. 我们需要做的检查可能会变得更加复杂 - 例如。检查权限,空间... - 我们可能需要检查的运行时选择性,感觉就像Check类的层次结构可能正在出现,重构的时间。
  2. 我们需要在另一个上下文中重用该检查。
  3. 检查代码本身变得复杂,我们需要重构它的代码以便我们理解它,我们专门为Check增加了许多实现功能。此时,我们的Create类变得杂乱无章,重构的时间。
  4. 随着复杂性的增加,我们看到需要单独测试Check,因此它已成为一流的类 - 需要自行记录和控制。

答案 1 :(得分:1)

我更倾向于将两种功能放在同一个类中。 OOP是关于将数据与单个对象中的行为相结合。在这种情况下,您的数据是您的路径和文件名,并且您有两个与该数据相关联的行为:检查存在和创建。

考虑到这一点,我认为将这个对象称为File而不是File + some verb会更像OOP。毕竟,OOP是关于对象的建模,该对象的动词是它的方法。

我的实现可能类似于:

public class File
{
    private readonly string path;

    public File(string path)
    {
        this.path = path;
    }

    public void Create()
    {
        if (!DoesFileExist())
        {
            // create file.
        }
    }

    private bool DoesFileExist()
    {
        // check if file exists.
    }
}

答案 2 :(得分:1)

答案是它可能并不重要;但是,单一责任类通常更具可重用性,特别是如果您有多重继承。除非有特定的理由将它们联系在一起,否则你可以将它们分开。

如果没有其他考虑,我可能会把这个例子写成一个类。然而,一旦它成为一个需要考虑的东西,你可能只是让它们分开。

答案 3 :(得分:0)

在这样一个简单的场景可能是最好的选择是第一,记住,软件设计的最终目标是生产系统简单易懂/修改/延伸,第一类是很容易理解的。

来自djna的答案非常好,重构时有明显的好处。当重构的日子到来时,考虑另一种选择,你有两个责任:

  • 创建文件
  • 仅在符合某些条件时创建

你可以这样:

class FileCreator

  def initialize(path, fileCreationCriteria)
    @path = path
    @fileCreationCriteria = fileCreationCriteria
  end

  def create_files
    unless fileCreationCriteria.meetCriteria?(path)
       #create files at path
    end
  end

end

然后你可以有不同的标准,例如文件已经退出,另一个例子可以是空间限制o。创建对象时,您可以:

file_creator = FileCreator.new('path', CreateIfNotExists.new)

file_creator = FileCreator.new('path', CreateAllwaysAndOverride.new)

file_creator = FileCreator.new('path', CreateUntilSpaceLimitIsReached.new('1GB'))

可能有一个默认标准可能是一个好主意,想想你的班级/ api的来电者可以轻松搞定。

显然,这是不是过度设计更加像最初的一个问题,你存在,它只是作为一个例子SRP和启闭(现在你的文件创建者的接近的修改和对扩展开放和只有一个责任)

请记住,模式和原则只是指南,总是取决于背景和设计师的良好判断。