在不违反 SOLID 原则的情况下使用具有不同方法名称的子类

Working with subclasses that have different method names without violating SOLID principles

//接口

public interface Singer{
    void sing();
}
public interface SongWriter{
    void writeSong();
}

//实现

public class PureSinger implements Singer{
    void sing(){}
}
public class SingerSongWriter implements Singer, SongWriter{
    void sing(){}
    void writeSong(){}
}

//客户端代码

void methodA(){
    Singer objPureSinger = new PureSinger();
    Singer objSingerSWer = new SingerSongWriter();

    doSomething(objPureSinger);
    doSomething(objSingerSWer);
}

public void doSomething(Singer obj){
    obj.sing();
    obj.writeSong();    //<--- this does not work.
}

为了实现这种代码,我应该如何设计class结构?

你不应该假设在 doSomething() 中使用 .writeSong() 因为你传递的参数是 Singer,而且我们知道 Singer 只有一个方法叫做。唱歌()。这里有一些选项。

  1. 您应该考虑 doSomething() 在业务逻辑意义上的实际作用。也许我们可以摆脱调用 .writeSong() 因为传入的参数并不总是可以转换为 SongWriter。
  2. 考虑使用基础 class(例如抽象 class 或具体 class)来实现 SingerSongWriter 将其作为参数数据类型传递。
  3. 如果您正在寻找快速修复来制作代码 运行,请参阅下文。

快速修复: 您需要首先查看 obj 是否是 SongWriter 的 instanceOf,因为传入的参数是 Singer 类型,它没有名为 .writeSong().

的方法
public void doSomething(Singer obj){
    obj.sing();
    //obj.writeSong();    //<--- this does not work.
    if (obj instanceOf SongWriter) songWriter.writeSong();
}

这是一个快速修复。您可以从下面的帖子中看到您应该使用 instanceOf last。

  • Is instanceof considered bad practice? If so, under what circumstances is instanceof still preferable?

为了快速回答问题 doSomething 调用了 sing()writeSong() 方法。只有您的 SingerSongWritter class 定义了这两个,因此是唯一可以同时执行这两个操作的 class。 objPureSinger 没有定义 writeSong 是什么,所以不知道调用时该做什么。

如果你想保留这个结构,你可以做一件事来解决这个问题,那就是在两个 class 中实现一个名为 do 的方法。在您的 PureSinger class 中,do 只是简单地调用 sing() 但在您的 SingerSongWriter class 中它同时调用 sing()writeSong()。最后在你的 doSomething 方法中调用 obj.do();

您可以根据业务需要设计 class。而且,很明显在

处得到编译时错误
public void doSomething(Singer obj){
    obj.sing();
    obj.writeSong();    //<--- compiler will complain here
}

因为Singer没有writeSong方法。根据您当前的设计:

  1. 全部 Singersing.
  2. 全部 SongWriterwriteSong.

但是,上面的none可以同时执行。所以,很明显 doSomething 直到

才有效
doSomething (SingerSongWriter obj)

因为,只有SingerSongWriter可以同时执行。

In order to acheve this type of code, how should I design the class structure?

首先定义一个名为 Artistinterface,它有一个名为 perform 的方法。接下来,定义两个子class,即SingerSongWriter,每个子perform分别实现了perform,并包含了唱歌和写歌的代码。

以下两种设计模式可以很好地支持您的用例:

  1. Decorator 设计模式:在您的例子中,ArtistComponentSingerSongWriter具体组件ArtistDecorator是您的抽象装饰器class。使用 ArtistDecoratorSinger 包装成 SongWriterdoSomething 方法接受一个 Artist 参数,并传递给最终修饰的 Artist 对象,该对象将 Singer 包装成 SongWriter.
  2. Composite 设计模式:在您的情况下 Arist 组件 CompositeArtistComposite 并且 SingerSongWriterLeaf具体组件 classes. doSomething 方法接受一个 Artist 参数。将 CompositeArtist 的一个实例传递给它(IS-A Artist)并且 doSomething 只是调用 perform,它在内部遍历所有Artist 个实例一个接一个地调用它们的 perform 方法。