Java 使用具有不同方法名称的子类而不违反实体原则
//接口Java 使用具有不同方法名称的子类而不违反实体原则,java,oop,design-patterns,polymorphism,mixins,Java,Oop,Design Patterns,Polymorphism,Mixins,//接口 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(){}
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.
}
void methodA(){
Singer objPureSinger=新的PureSinger();
Singer objSingerSWer=新歌手SongWriter();
doSomething(objPureSinger);
doSomething(objSingerSWer);
}
公共无效剂量测定(Singer obj){
obj.sing();
obj.writeSong();//您不应该假设在doSomething()中使用.writeSong(),因为您以Singer的身份传递参数,我们知道Singer只有一个名为.sing()的方法。下面是一些选项
<> LI>您应该考虑在业务逻辑意义上实际做什么(可能),也许我们可以去掉调用.WrreSeNe(),因为传入的参数并不总是可以向歌曲编写者浇铸。
考虑使用基类(例如抽象类或具体类)实现Singer和SongWriter,将其作为参数数据类型传入
如果您正在寻找一个快速修复程序来运行代码,请参阅下面的内容
快速修复:
您首先需要查看obj是否是SongWriter的实例,因为传入的参数类型为Singer,而Singer没有名为.writeSong()的方法
public void doSomething(Singer obj){
obj.sing();
//obj.writeSong();//要快速回答问题doSomething
调用sing()
和writeSong()
方法。只有您的SingerSongWriter
类同时定义了这两种方法,并且是唯一可以同时执行这两种方法的类。objPureSinger
没有定义什么是writeSong
,因此调用时不知道该做什么
如果你想保持这种结构,你可以在两个类中都实现一个名为do
的方法。在PureSinger
类中,do
只需调用sing()
,但在SingerSongWriter
类中它同时调用sing()
和writeSong())
。最后,在您的doSomething
方法中,只需调用obj.do();
您就可以根据业务需要设计类。而且,很明显,在
public void doSomething(Singer obj){
obj.sing();
obj.writeSong(); //<--- compiler will complain here
}
因为只有歌手SongWriter才能同时执行这两项操作
为了实现这类代码,我应该如何设计类结构
首先定义一个名为Artist
的接口
,该接口有一个名为perform
的方法。接下来,定义两个子类,即Singer
和SongWriter
,每个子类实现perform
,并包含分别用于唱歌和写歌的代码
以下两种设计模式将非常好地支持您的用例:
设计模式:在你的例子中,Artist
是组件,Singer
和SongWriter
是具体的组件,ArtistDecorator
是你的抽象装饰类。使用ArtistDecorator
将歌手
包装成歌曲作者
。doSomething
方法od接受一个Artist
参数,并传递最终装饰的Artist
对象,该对象将歌手
包装成歌曲作者
设计模式:在您的案例中,Arist
是组件。compositeratist
是复合的,Singer
和SongWriter
是叶子或具体的组件类。doSomething
方法采用Artist
参数。将compositeratist的实例传递给它ode>(它是一个Artist
)和doSomething
只是调用perform
,它在内部逐个迭代调用其perform
方法的所有Artist
实例
目标是用一个基本接口/抽象类对象控制PureSinger和SingerSongWriter对象。根据您的设计,您应该使用SingerSongWriter
作为doSomething()
的参数,您希望doSomething(objPureSinger);
做什么?这样,我就不能将objPureSinger传递给doSomething()@再次重申,OP不希望歌手写歌。相反,OP希望歌手唱歌,写歌人写歌。他还希望歌手写歌,写歌人可以唱歌和写歌。这项功能需要使用单一界面来支持,而不必真正担心doSomething
传递给它的具体类型。我同意Singer
接口名称令人困惑,可以将其重命名为Artist
,并且doSomething
可以作为Artist
的参考。希望这能澄清问题。(我已经在回答中介绍了解决方案)将来可能会添加新接口或新Singer的具体类,因此“if(obj instanceOf)…”违反实体的OCP。我需要一个实现OCP的设计。因此您有两个选项。第一个选项是创建一个基类来实现这两个方法,并将其作为参数数据类型传递。另一个选项是不调用.writeSong()在doSomething()方法中(重新访问您的业务需求)。我认为这违反了SOLID的LSP。纯歌手不写任何歌曲。如果你想让dosomething方法对两个人都有效,试试新的建议,它只是在两个类中都添加了一个名为相同的方法。@Federicoperaltachafner关于复合模式不适合这里的评论:在复合模式的情况下eCompositeAritst
将在数组/列表中包含一个Singer
实例和一个SongWriter
实例。这将共同构成一个歌手-歌曲作者的合成。你能详细说明你所说的没有合成,只有单叶对象吗?嗯……我的意思是合成是我们的一种模式
public void doSomething(Singer obj){
obj.sing();
obj.writeSong(); //<--- compiler will complain here
}
doSomething (SingerSongWriter obj)