代码之家  ›  专栏  ›  技术社区  ›  Antoine Claval

空抽象类是一种糟糕的做法吗?为什么?

  •  10
  • Antoine Claval  · 技术社区  · 15 年前

    我们的代码库中有几个空的抽象类。我觉得那很难看。但是除了这个非常愚蠢的原因(丑陋),我是否应该重构它(例如,重构为空接口)?

    否则,代码是健壮的,并且经过良好测试。因此,如果只是出于“美学”的原因,我将通过并保留空的抽象类。

    编辑:

    1) 所谓“空抽象类”,我的意思是:

    public abstract class EmptyAbstractClass {}
    

    2) “空虚”的原因是:冬眠。我根本不掌握这个持久性框架。我只知道接口不能映射到表,出于这个技术原因,类比接口更受欢迎。

    11 回复  |  直到 13 年前
        1
  •  5
  •   xlm santhosh reddy    3 年前

    在我看来,这似乎是创建一个对象层次结构的结果,该层次结构的顶层没有任何公共功能。我怀疑直接子类本身是抽象的,或者至少有自己的子类。另一种可能是您的代码有很多 instanceof 功能分散在各处。

    最顶层的空级别本身并不是什么大问题,但我会检查以确认实际上不存在任何公共功能。假设它确实存在,我将考虑在父类中提取公共特性。我一定会留意的 运算符 认真考虑重构它。有关示例,请参阅重构到模式(Kerievsky)。

        2
  •  19
  •   Vincent Ramdhanie    15 年前

    如果现在绝对没有直接影响,我就不会碰它。如果出现需要您进行更改的维护事件,那么我将重构它,因为我已经在代码中了。

    换句话说,如果它没有坏,就不要修理它。

        3
  •  8
  •   David Seiler    15 年前

        4
  •  7
  •   extraneon    15 年前

    它不一定比替代方案更难看,替代方案可能是重复代码。

    在理想情况下,您将能够仅使用接口进行建模。例如:

    在这种情况下,你需要制造和抽象汽车。

    所以我想这是品味的问题。

    一个警告;如果您使用大量代理类,如Spring和一些测试框架,那么并行接口层次结构可能会导致更少的意外错误。

        5
  •  2
  •   BlairHippo    15 年前

    问你自己这样一个问题:如果由于你的重构,生产中出现了一些问题,而你的继续工作取决于你花时间修复一些实际上没有出现问题的问题的合理性,你会怎么说?

    “这对我来说既丑陋又有审美上的冒犯”并不是我想拿我的工作打赌的答案。

    在这个阶段,我说要谨慎行事,和丑陋的人一起生活。

        6
  •  2
  •   Pascal Thivent    15 年前

    空的抽象类对我来说没有任何意义,抽象类应该用来继承一些行为。所以,我倾向于同意,这是一个非常丑陋的设计,而且抽象类的使用非常糟糕,标记接口应该是首选。所以你有两个选择:

    在这种特殊的情况下,实际的设计目前确实没有什么坏处,所以你可以接受它。然而,我认为替换这些抽象类是一个非常简单的重构(使它们成为接口并替换它们) extends implements 我真的看不出什么东西会被破坏,所以我会去做。

    如果它没坏,就别修了 ,你永远不会重构任何东西(“我的测试通过了,我为什么要重构?”)。冻结代码绝对不是正确的解决方案, .

        7
  •  2
  •   BalusC    15 年前

    关键是,您可以从 抽象类,而您可以实现

    显然,“空抽象类”的设计决定是为了防止实现类从另一个类扩展。

    如果是我,我就让它走,否则它可能会碎。最好还是联系最初的开发人员并要求他们进行推理(为了方便您和将来的工作,将它们作为注释添加到抽象类中)。

        8
  •  1
  •   Monachus    15 年前

    根据面向对象编程理论,继承的主要目的是多态性、代码重用和封装。一个空的抽象类(当我这么说的时候,我指的是真正的空,没有构造函数,没有方法,没有属性)。没什么无法实现此编程技术所希望的三个目标中的任何一个。相当于 if(true){...} . 将其更改为接口并不能真正使其变得更好。

    如果你想重构代码,我建议你朝着相反的方向思考,我的意思是:尝试从共享抽象父类的所有类中抽象属性、方法和构造函数。

    这是一项艰巨的工作,短期内几乎没有回报,但它极大地提高了代码的可维护性,因为核心逻辑更改只需执行一次。我怀疑使用这些空抽象类的原因是为了识别一组必须共享某些共同点的类,否则它们之间会有什么区别 Object 和抽象类

        9
  •  0
  •   TofuBeer    15 年前

    如果您有以下模式,您会发现它是最灵活的:

    interface Fooable
    {
       void foo();
       void bar();
    }
    
    abstract class AbstractFoo
        implements Fooable
    {
    }
    
    class Foo
        extends AbstractFoo
    {
       public void foo()
       {
       }
    
       public void bar()
       {
       }
    }
    

    通过这种方式,您可以始终通过接口,但是如果您以后发现您有一些通用的代码,您可以将其放入抽象类中,而无需对所有类进行更改。

    除非你有一个很好的理由不使用这种模式(我怀疑你在这种情况下没有),否则我建议你使用它。这可能会导致空的抽象类,但我认为这是可以的(有点奇怪,但还行)。

    如果接口中确实没有方法或只有一个方法,那么我将跳过抽象类。

    从编译器/函数的角度来看,接口和所有方法都是抽象的抽象类之间没有真正的区别。接口将比抽象类更灵活,接口+抽象类将是最灵活的。

    如果是我的代码,我会把它们改成接口。。。

        10
  •  0
  •   Jay    15 年前

    显而易见的问题是,为什么要放在那里?它是如何使用的?

    我的猜测是,要么(a)这是一些错误开始的痕迹。早期的草稿在抽象类中有一些数据或函数,但随着程序员的工作,这些数据或函数都被移到了其他地方,直到只剩下一个空壳。但更可能的是(b)在某个点上有一个代码说“if(x instanceof…”。我认为这是一个糟糕的设计,基本上使用类成员身份作为标志。如果您需要一个标志,请创建一个标志,不要通过创建一个类或接口然后将其用作标志来假装您“更面向对象”。这可能符合一些教科书中关于更好编码的定义,但实际上只会让代码更加混乱。

        11
  •  0
  •   James McMahon    13 年前

    虽然我没有得到空类映射到的表中的内容,但如果该类有某种用途,那么,请保留它,直到有机会重构一些。

    我肯定要做的是:写一条注释,说明这个类为什么存在于文件中。干净而“漂亮”的代码的一个重要原因是不要让其他开发人员思考。注释可以帮助实现这一点,即使代码没有它可能的那么漂亮。