我正在重构一些代码,并希望继承链中的类更高一些,对它们的参数要严格一些。由于我不确定我是否正确解释了这一点,这就是我所拥有的:
public interface ISvdPredictor
{
List<string> Users { get; set; }
List<string> Artists { get; set; }
float PredictRating(ISvdModel model, string user, string artist);
float PredictRating(ISvdModel model, int userIndex, int artistIndex);
}
ISvdPredictor
使用ISvdModel
:
public interface ISvdModel
{
float[,] UserFeatures { get; set; }
float[,] ArtistFeatures { get; set; }
}
现在我想实现另一种变体:
public interface IBiasSvdPredictor : ISvdPredictor
{
float PredictRating(IBiasSvdModel model, string user, string artist);
float PredictRating(IBiasSvdModel model, int userIndex, int artistIndex);
}
使用IBiasSvdModel
派生的ISvdModel
:
public interface IBiasSvdModel : ISvdModel
{
float GlobalAverage { get; set; }
float[] UserBias { get; set; }
float[] ArtistBias { get; set; }
}
IBiasSvdPredictor
不适用于ISvdModel
。
问题在于,当我实现IBiasSvdPredictor
时,我必须实现2对PredictRating方法。一个来自ISvdPredictor
,另一个来自IBiasSvdPredictor
。我需要做些什么才能实现IBiasSvdPredictor
中的那些?
我也尝试过泛型,但无法使用PredictRating
指令将BiasSvdPredictor
的{{1}}限制为IBiasSvdModel
。我可能做错了所以任何建议都可能有所帮助。我想你得到了我想做的事。
编辑:如果有人需要更多上下文,请参阅https://github.com/gligoran/RecommendationSystem。我正在为BSc的论文编写这段代码。
答案 0 :(得分:4)
您可以使用泛型和约束。
public interface ISvdModel
{
float[,] UserFeatures { get; set; }
float[,] ArtistFeatures { get; set; }
}
public interface IBiasSvdModel : ISvdModel
{
float GlobalAverage { get; set; }
float[] UserBias { get; set; }
float[] ArtistBias { get; set; }
}
public interface ISvdPredictor<in TSvdModel>
where TSvdModel : ISvdModel // Require that TSvdModel implements ISvdModel
{
List<string> Users { get; set; }
List<string> Artists { get; set; }
float PredictRating(TSvdModel model, string user, string artist);
float PredictRating(TSvdModel model, int userIndex, int artistIndex);
}
// I would actually avoid declaring this interface. Rather, see comment on the class.
public interface IBiasSvdPredictor : ISvdPredictor<IBiasSvdModel> { }
class BiasSvdPredictor : IBiasSvdPredictor // Preferred : ISvdPredictor<IBiasSvdModel>
{
// ...
public float PredictRating(IBiasSvdModel model, string user, string artist) { }
public float PredictRating(IBiasSvdModel model, int userIndex, int artistIndex) { }
}
答案 1 :(得分:2)
interface
应该有一个方法,PredictRating。我不会有两个具有相同方法的接口。混乱。
创建一个实现abstract
的{{1}}类。使PredictRating成为interface
方法,以便继承者可以根据需要覆盖它们。您甚至可以在抽象类上执行默认实现。
一个界面,一个抽象类。 N具体实现PredictRating的具体类。
virtual
答案 2 :(得分:1)
您必须实施所有四种方法。它们具有不同的签名,因此被认为是不同的。但是,您可以将一个委托给另一个委托,有时使用显式实现有助于此。
public class Foo : IBiasSvdPredictor {
public float PredictRating(IBiasSvdModel, string user, string artist) { .... }
// this is an expicit implementation of ISvdPredictor's method. You satisfy
// the interface, but this method is not a public part of the class. You have to
// cast the object to ISvdPredictor in order to use this method.
float ISvdPredictor.PredictRating(ISvdModel model, string user, string artist) {
this.PredictRating((IBiasSvdModel)model, user, artist);
}
}
如果ISvdModel实际上不是IBiasSvdModel,这当然行不通。
答案 3 :(得分:0)
您可以使用显式接口实现隐藏ISvdPredictor
中的那些,但您应该全部实现它们或者有一个基本抽象类来处理它们。
答案 4 :(得分:0)
我必须实现2对PredictRating方法。
你当然可以。你有什么期望?
如果您的IBiasSvdPredictor
必须在其IBiasSvdModel
方法中使用PredictRating
,则IBiasSvdPredictor
不 ISvdPredictor
(因为它不能将ISvdModel
作为PredictRating
的第一个参数)并且从IBiasSvdPredictor
继承ISvdPredictor
是错误的选择。
在我看来,你应该简单地将接口分开,而不是从另一个继承接口。
答案 5 :(得分:0)
如果没有完全理解你的对象模型(所以这可能不适用于你的情况),似乎ISvdModel
可能不应该是接口定义的一部分。它似乎更像是一个实现细节,不一定是您试图强制执行的合同的一部分。对我来说,将ISvdModel
(或IBiasSvdModel
)传递给实现类的构造函数更有意义,而不是将它作为ISvdPredictor
接口的一部分。那么你根本不需要2个独立的接口定义,你只需要2个单一接口的实现。
你甚至可以更进一步;如果ISvdPredictor
和IBiasSvdPredictor
之间的唯一区别是使用ISvdModel
而另一个使用IBiasSvdModel
,那么您甚至不需要2个实现,只需要一个,你会为每种情况传递ISvdModel
的正确实例。这是一种名为Inversion of Control的设计模式,特别是使用依赖注入,并且非常强大,可以在程序中实现更高级别的代码重用。