从具体类继承的任何好例子?

sle*_*ske 73 java oop inheritance liskov-substitution-principle

背景:

作为Java程序员,我从接口广泛继承(而不是:实现),有时我设计抽象基类.但是,我从来没有真正觉得需要子类化一个具体的(非抽象)类(在我这样做的情况下,后来发现另一个解决方案,例如委托会更好).

所以现在我开始觉得几乎没有从具体类继承的合适的情况.一方面,Liskov替换原则(LSP)似乎几乎不可能满足非平凡类; 还有许多其他问题,这里似乎呼应了类似的意见.

所以我的问题:

在哪种情况下(如果有的话)从具体类继承它真的有意义吗?你能给出一个继承自另一个具体类的类的具体的,真实的例子吗?你觉得这是给定约束的最佳设计吗?我对满足LSP的示例(或满足LSP似乎不重要的示例)特别感兴趣.

我主要有Java背景,但我对任何语言的例子感兴趣.

Dav*_*Far 20

您经常有一个接口的骨架实现I.如果你可以在没有抽象方法的情况下提供可扩展性(例如通过钩子),那么最好有一个非抽象的骨架类,因为你可以实例化它.

一个示例是转发包装类,以便能够转发到C实现的具体类的另一个对象I,例如,无需继承就能够进行装饰或简单的代码重用.您可以在Effective Java第 16项中找到这样的示例,支持组合而不是继承.(我不想在这里发布它,因为版权,但它实际上只是转发包装实现的所有方法调用).CCI

  • +1用于骨架实现.如果没有Swing的"适配器"类(`MouseAdapter`等)来提供多方法事件监听器接口的NOOP实现,那么GUI组件编写起来会更加痛苦. (9认同)

And*_*rey 18

我认为以下是适当的一个很好的例子:

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
Run Code Online (Sandbox Code Playgroud)

另一个很好的例子是异常的继承:

public class IllegalFormatPrecisionException extends IllegalFormatException
public class IllegalFormatException extends IllegalArgumentException
public class IllegalArgumentException extends RuntimeException
public class RuntimeException extends Exception
public class Exception extends Throwable
Run Code Online (Sandbox Code Playgroud)

  • 对例外的继承确实是一个好点.至于HashMap/LinkedHashMap:为什么你觉得这是一个很好的例子?让两者都从接口/抽象类继承是不是更清晰? (6认同)

Kei*_*thS 14

我能想到的一个非常常见的情况是从基本的UI控件中获取,例如表单,文本框,组合框等.它们是完整的,具体的,并且能够独立存在; 但是,它们中的大多数也非常基本,有时它们的默认行为不是你想要的.例如,几乎没有人会使用未掺杂表单的实例,除非他们可能正在创建一个完全动态的UI层.

例如,在我写的一个软件中,最近达到相对成熟度(意思是我没时间专注于开发它:)),我发现我需要为ComboBox添加"延迟加载"功能,所以它不会'加载第一个窗口需要50年(计算机年).我还需要能够根据另一个ComboBox中显示的内容自动过滤一个ComboBox中的可用选项,最后我需要一种方法在另一个可编辑控件中"镜像"一个ComboBox的值,并在一个控件中进行更改.其他的.因此,我扩展了基本的ComboBox,为它提供了这些额外的功能,并创建了两种新类型:LazyComboBox,然后是MirroringComboBox.两者都基于完全可用的,具体的ComboBox控件,只是覆盖了一些行为并添加了其他一些行为.它们不是非常松散耦合,因此也不是太过SOLID,但是增加的功能足够通用,如果必须的话,我可以从头开始重写这些类中的任何一个来做同样的工作,可能更好.


S.L*_*ica 12

一般来说,我从具体课程中获得的唯一时间就是他们在框架中.从简单的例子中得到AppletJApplet成为琐碎的例子.


Buh*_*ndi 7

这是我正在进行的当前实施的一个例子.

在OAuth 2环境中,由于文档处于草稿阶段,因此规范不断变化(截至编写时,我们的版本为21).

因此,我不得不扩展我的具体AccessToken类以适应不同的访问令牌.

在早期的草案中,没有token_type字段集,因此实际的访问令牌如下:

public class AccessToken extends OAuthToken {

    /**
     * 
     */
    private static final long serialVersionUID = -4419729971477912556L;
    private String accessToken;
    private String refreshToken;
    private Map<String, String> additionalParameters;

    //Getters and setters are here
}
Run Code Online (Sandbox Code Playgroud)

现在,有了返回的Access令牌token_type,我有

public class TokenTypedAccessToken extends AccessToken {

    private String tokenType;
    //Getter and setter are here...
}
Run Code Online (Sandbox Code Playgroud)

所以,我可以返回两者,最终用户不是更聪明.:-)

总结:如果您希望自定义类具有与具体类相同的功能而不更改具体类的结构,我建议扩展具体类.


San*_*osh 6

其他用例是覆盖默认行为:

可以说有一个类使用标准的Jaxb解析器进行解析

public class Util{

    public void mainOperaiton(){..}
    protected MyDataStructure parse(){
        //standard Jaxb code 
    }
} 
Run Code Online (Sandbox Code Playgroud)

现在说我想使用一些不同的绑定(Say XMLBean)进行解析操作,

public class MyUtil extends Util{

    protected MyDataStructure parse(){
      //XmlBean code code 
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以使用新的绑定代码重用超类.

  • 好点子.当然,这里的继承是必要的,因为基类愚蠢地忽略了为解析器使用依赖注入...... (2认同)
  • 更一般地说,OP就是这样的情况:"......另一种解决方案,例如授权本来会更好." (2认同)

Aak*_*shM 6

我主要有Java背景,但我对任何语言的例子感兴趣.

与许多框架一样,ASP.NET大量使用继承来共享类之间的行为.例如,HtmlInputPassword具有此继承层次结构:

System.Object
  System.Web.UI.Control
    System.Web.UI.HtmlControls.HtmlControl          // abstract
      System.Web.UI.HtmlControls.HtmlInputControl   // abstract
        System.Web.UI.HtmlControls.HtmlInputText
          System.Web.UI.HtmlControls.HtmlInputPassword
Run Code Online (Sandbox Code Playgroud)

其中可以看到从中派生出来的具体类的例子.

如果您正在构建一个框架 - 并且您确定要这样做 - 您可能会发现自己想要一个漂亮的大继承层次结构.