OO风格 - 简单问题

问题描述:

简单的问题,为所有你务实的面向对象的家伙。 我已经多次阅读以避免像“处理器”和“xxxxHandler”这样的类来同意OO标准:并且我相信这是衡量系统代码可读性的好方法。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

不应该这个我社区维基? (我不敢相信自己已经成为提出这个问题的人之一。) – Imagist 2009-08-17 05:25:37

我认为你所描述的是对象应该照顾只需要自己的操作,这通常是一条很好的规则。只要“处理”一些不同的(但相关的)事物,“处理器”类没有什么不对。但是如果你有一个只处理一件事的类(比如一个CSV解析器只解析CSV),那么真的没有理由让处理器不处理它自己。

但是,打破这一规则有一个共同的原因:通常你不想做你不需要做的事情。例如,对于你的CSV类,如果你只想找到第一个单元格是“Bob”的CSV行并获得该行的第三列(也就是说,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是高级抽象。

+0

不得不选择它,因为它已经打开了我的眼睛:我有点想知道我如何抽象CSVParser。在这个时候,它只会对文件进行只读操作..但是最终会改变需求。我会采取sipwiz的建议,让对象做它需要的。多谢你们。 – 2009-08-17 12:03:18

我同意你的哲学,但如果是我,我可能会调用CsvFile类,除了Scan之外,还有一个Parse方法。在面向对象编程中,总是希望让你的类代表“事物”(英文名词)。

除此之外,如果我被要求维护你的代码,我会掌握一个CsvParser类可能会做的事情,而MyFileScan会让我陷入愤怒之中,并导致我不得不阅读代码才能解决问题。

+0

另外,命名为“MyX”的东西让我发狂。如果你给出一个非常一般的解释性例子,比如MyObject或者MyClass(尽管在这种情况下我会用metasyntactic变量:foo,bar,baz,qux,quux,corge,grault,garply,waldo,fred, plugh,xyzzy,thud)。但是如果你打算使用类来做任何事情,我想看到CSV而不是MyCSV。这个CSV属于谁,他们为什么要求拥有所有权? – Imagist 2009-08-17 05:23:12

+0

的确是正确的,我完全同意。我在这里使用“我的”作为示例。我想保持在我的领域,而不使用富,酒吧等。好点。 – 2009-08-17 11:55:06

这是问题域与解决方案域设计。

为了解决问题,我们可以设计我们的类来模拟真实生活对象,也就是根据问题领域的程序。

另一种编程方式是根据Solution Domain进行设计。例如,当我们设计一个航班预订系统时,对于航班管理专家,他们会将航班描述描述为“航线”,“时间”,“角度”(我不能真正记得这个词)。如果我们根据这些模型进行设计,则根据问题域将其称为设计。我们也可以使用坐标系(x,y,z)进行设计,因为我们认为作为程序员,我们可以更高效地处理这些问题。这是Solution Domain的设计。

解决方案领域的问题是,在项目的世界里,一个不变的东西是 - 改变!这些要求将永远改变!如果要求发生变化,则必须重新设计程序。

但是,如果您将类建模为现实生活对象,那么受更改的影响较小,因为现实生活中的对象很少发生变化。

“Processor”和“xxxxHandler”< - 这是设计到解决方案域。

你可以看看Domain-Driven Design --- DDD的短裤。

+0

我明白了,我明白了......一定会研究它 - 当我说话的时候“*”。你看,我认为这与思维过程有很大关系。我们如何对事物建模。你基本上说,我们如何使用这些对象比对象本身更有可能改变?还是我误读了。 谢谢 – 2009-08-17 11:59:03

+0

我在说,客户的要求总是在变化。如果我们根据现实生活模型设计我们的课程,它将不受需求变化的影响。 – janetsmith 2009-08-17 12:20:41