2008-11-13 64 views
6

我想用一种特定的方法解析一个Apache access.log文件,尽管我对于面向对象编程是全新的,但我现在要开始做。从内建类继承是否正确?

我要创建一个类ApacheAccessLog,我现在可以想像的唯一的事情,它会做的是“的readline”的方法。在这种情况下继承文件类是否通常是正确的,因此该类将表现得类似文件类本身的实例,或者不是?这样做的最好方法是什么?

回答

15

在这种情况下,我会使用代表团而不是继承。这意味着你的类应该包含文件对象作为属性,并在其上调用readline方法。您可以在记录器类的构造函数中传递一个文件对象。

至少有两方面的原因:

  1. 代表团在地方文件的对象,你可以用它实现了一个readline方法(鸭打字来得心应手这里)任何其他对象减少耦合,例如。
  2. 从文件继承时,类的公共接口变得不必要的宽泛。它包含文件中定义的所有方法,即使这些方法在Apache日志中没有意义。
1

从内置类继承是完全可以接受的。在这种情况下,我会说你是对的。
日志“是”文件,以便告诉您继承是否正常。

一般规则。
狗“是一种”动物,因此继承了动物。
所有者“有”n动物因此不从动物继承。

1

虽然在某些情况下从内建继承是有用的,但真正的问题在于您想要如何处理输出以及您的大图设计。我通常会写一个阅读器(使用一个文件对象)并吐出我需要的任何数据类来保存我刚刚阅读的信息。那么设计这个数据类就很容易,以适应我的其余设计。

1

从“内建”类继承,您应该相当安全,因为后面对这些类的修改通常与当前版本兼容。

但是,您应该认真思考一下,您是否真的想将您的课程与内置课程提供的附加功能联系起来。正如在另一个答案中提到的,你应该考虑(或许更喜欢)代替代表

作为避免继承的一个例子,如果您不需要它,您可以查看java.util.Stack类。当它扩展Vector时,它继承了Vector上方法的全部。这些方法中的大多数都打破了Stack所暗示的契约,例如,后进先出法。在内部使用Vector来实现Stack会更好,只会将Stack方法暴露为API。然后很容易将实现更改为ArrayList或稍后的其他东西,但由于继承原因,现在没有可能。

6

我来自Java的背景,但我相当相信,相同的原则将适用于Python。作为一个经验法则,你应该从来没有继承自你不明白和控制的实现类,除非该类是专门为继承而设计的。如果它是以这种方式设计的,它应该在文档中清楚地说明这一点。

原因是继承可能会将您绑定到您正在继承的类的实现细节。

要使用从乔希布洛赫的书为例“有效的Java”

如果我们为了扩展类ArrayList类能算在其生命时间加入到它的项目的数量(不一定是它当前包含的数字),我们可能会试图写这样的东西。

public class CountingList extends ArrayList { 
    int counter = 0; 

    public void add(Object o) { 
     counter++; 
     super.add(0); 
    } 

    public void addAll(Collection c) { 
     count += c.size(); 
     super.addAll(c); 
    } 

    // Etc. 
} 

现在这个扩展看起来像它会精确计算被添加到列表中的元素的数量,但实际上它可能不会。如果ArrayList已通过遍历所提供的Collection并对其每个元素调用其接口方法addAll来实现addAll,那么我们将统计通过addAll方法添加的每个元素两次。现在我们班的行为取决于ArrayList的实施细节。

这当然是除了不能使用List的其他实现与我们的CountingList类的缺点。加上从上面讨论的具体类继承的缺点。

我的理解是Python对Java使用类似的(如果不是相同的)方法调度机制,因此会受到相同的限制。如果有人能够在Python中提供示例,我相信它会更有用。

0

你似乎已经找到了你的答案,在这种情况下,委派是更好的策略。尽管如此,我想补充一点,除了代表团之外,扩展内置类没什么问题,特别是如果您的替代方案取决于语言是“猴子修补程序”(参见http://en.wikipedia.org/wiki/Monkey_patch