对于所有务实的面向对象的人来说,这是一个简单的问题。 我已多次阅读以避免类似“处理器”和“xxxxHandler”这样的类,以便同意OO标准:我认为这是系统代码可理解性的一个很好的衡量标准。
假设我们有一个扫描某些文件结构的软件,比方说一堆特定的CSV文件。假设我们有一个名为CsvParser的独立模块。
class CsvParser {
public string GetToken(int position) { .. }
public bool ReadLine() { .. }
}
class MyCsvFile {
public string FullPath { get; }
public void Scan() {
CsvParser csvp(FullPath);
while (csvp.ReadLine())
{
/* Parse the file that this class represents */
}
}
}
这将节省一个“FileScanner”类,它是一个-Processor类型的类。收集的东西说,来自目录的一堆文件,并扫描每个。
class MyFileScan {
public string[] Files { get; set; }
public void GetFiles() { this.Files = Directory.GetFiles(..); }
public void ScanFiles() {
foreach (string thisFilePath in Files)
{
CsvParser csvp(thisFilePath);
/* ... */
}
}
}
OO方法规定了MyCsvFile类,然后是表示对象操作的方法。
有什么想法?你是程序员的想法。
答案 0 :(得分:3)
我同意你的观点,但如果是我,我可能会称之为CsvFile类,除了Scan之外还有一个Parse方法。在面向对象编程中,总是希望让你的类代表“事物”(英语名词)。
除此之外,如果我被要求维护你的代码,我会掌握CsvParser类可能会做什么,而MyFileScan会让我陷入愤怒之中,导致我必须阅读代码来解决它。< / p>
答案 1 :(得分:1)
这是问题域与解决方案域设计。
为了解决问题,我们可以设计我们的类来模拟现实生活对象,即根据问题域的程序。
另一种编程方式是根据Solution Domain进行设计。
例如,当我们设计飞行预订系统时,对于飞行管理专家,他们会将飞行旅行描述为“路线”,“时间”,“角度”(我真的不记得这个术语)。如果我们根据这些模型进行设计,则根据问题域称为设计。
我们也可以使用坐标系(x,y,z)进行设计,因为我们觉得作为程序员,我们可以更有效地处理这些问题。这是解决方案域的设计。
解决方案域的问题是,在项目的世界中,一个不变的是 - 更改!要求总会改变!如果要求发生变化,您必须重新设计程序。
但是,如果将类建模为真实对象,则受变化的影响较小,因为现实对象很少会发生变化。
“处理器”和“xxxxHandler”&lt; - 这是针对解决方案域的设计。
你可以看一下Domain-Driven Design --- DDD for short。
答案 2 :(得分:1)
我认为你所描述的是对象应该处理只需要自己的操作,这通常是一个很好的规则。 “处理器”类没有任何问题,只要它“处理”一些不同(但相关)的东西。但是如果你有一个只处理一件事的类(比如CSV解析器只解析CSV),那么处理器处理的东西就没有理由不对它自己进行处理。
然而,有一个共同的理由违反这条规则:通常你不想做你不必做的事情。例如,对于您的CSV类,如果你想要的只是在CSV中找到第一个单元格为“Bob”的行并获取该行中的第三列(也就是Bob的出生日期),那么你就不要我想读取整个文件,解析它,然后搜索你刚创建的漂亮的数据结构:它效率低下,特别是如果你的CSV有100K行,Bob的条目在第5行。
您可以重新设计CSV类以对CSV进行小规模操作,例如跳到下一行并获取第一个单元格。但是现在你正在实现你不会真正谈论CSV的方法。 CSV不读取行,它们存储它们。他们没有找到细胞,他们只是拥有它们。此外,如果你想进行大规模的操作,比如读取整个CSV并按第一个单元格排序,那么你会希望你在整个文件中读取旧的方法,解析它,然后翻过来。您创建的整个数据结构。您可以在同一个类中执行这两个操作,但现在您的类实际上是两个类,用于两个不同的目的。你的班级已经失去了凝聚力,你创造的任何班级实例都会有两倍的行李,而你只能使用一半。
在这种情况下,对CSV(对于大规模操作)和低级操作的“处理器”类进行高级抽象是有意义的。 (以下是用Java编写的,因为我知道比我更了解C#):
public class CSV
{
final private String filename;
private String[][] data;
private boolean loaded;
public CSV(String filename) { ... }
public boolean isLoaded() { ... }
public void load() { ... }
public void saveChanges() { ... }
public void insertRowAt(int rowIndex, String[] row) { ... }
public void sortRowsByColumn(int columnIndex) { ... }
...
}
public class CSVReader
{
/*
* This kind of thing is reasonably implemented as a subclassable singleton
* because it doesn't hold state but you might want to subclass it, perhaps with
* a processor class for another tabular file format.
*/
protected CSVReader();
protected static class SingletonHolder
{
final public static CSVReader instance = new CSVReader();
}
public static CSVReader getInstance()
{
return SingletonHolder.instance;
}
public String getCell(String filename, int row, int column) { ... }
public String searchRelative(String filename,
String searchValue,
int searchColumn,
int returnColumn)
{ ... }
...
}
类似的众所周知的例子是SAX和DOM。 SAX是低级,细粒度的访问,而DOM是高级抽象。