c#中的继承问题
本文关键字:问题 继承 | 更新日期: 2023-09-27 18:06:06
我正在重构一些代码,希望在继承链中更高一点的类对它们的参数更严格一点。由于我不确定我的解释是否正确,以下是我得到的:
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);
}
使用由ISvdModel
衍生而来的IBiasSvdModel
:
public interface IBiasSvdModel : ISvdModel
{
float GlobalAverage { get; set; }
float[] UserBias { get; set; }
float[] ArtistBias { get; set; }
}
IBiasSvdPredictor
不能与ISvdModel
一起工作。
问题是,当我实现IBiasSvdPredictor
时,我必须实现2对预测方法。一个来自ISvdPredictor
,另一个来自IBiasSvdPredictor
。我需要做些什么才能实现那些从IBiasSvdPredictor
?
我也尝试过泛型,但不能使用where
指令将BiasSvdPredictor
的PredictRating
限制为IBiasSvdModel
。我可能做错了,所以任何建议可能会有所帮助。我想你明白我的意思了。
编辑:如果有人需要更多的背景,请参阅https://github.com/gligoran/RecommendationSystem。我正在为我的学士学位论文写这段代码。
可以使用泛型和约束。
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) { }
}
interface
应该有一个方法PredictRating。我不会让两个接口实现相同的方法。混乱。
创建实现interface
的abstract
类。使PredictRating成为virtual
方法,以便继承者可以在他们认为合适的时候重写。你甚至可以在抽象类上做一个默认实现。
一个接口,一个抽象类。N个实现他们认为合适的predictring的具体类。
public interface Demo
{
int PredictRating(int param1);
}
public abstract class AbstractDemo : Demo
{
public virtual int PredictRating(int param1)
{
return param1 + 1;
}
}
public class ClassDemo1 : AbstractDemo
{
//This guy uses AbstractDemo Predict Rating
public override int PredictRating(int param1)
{
return base.PredictRating(param1);
}
}
public class ClassDemo2 : AbstractDemo
{
//This guy overrides the predict rating behavior
public override int PredictRating(int param1)
{
return param1 + 2;
}
}
您必须实现这四个方法。它们具有不同的特征,因此被认为是不同的。然而,你可以有一个委托给另一个,有时使用显式实现有助于这一点。
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,这当然不起作用。
您可以使用显式接口实现来隐藏ISvdPredictor
的接口,但您应该实现它们全部或有一个基本抽象类来处理它们
我必须实现两对PredictRating方法。
你当然知道。你想要什么?
如果您的IBiasSvdPredictor
必须在其PredictRating
方法中取IBiasSvdModel
,则IBiasSvdPredictor
是而不是和ISvdPredictor
(因为它不能将ISvdModel
作为PredictRating
的第一个参数),从ISvdPredictor
继承IBiasSvdPredictor
是错误的选择。
在我看来,你应该简单地保持接口的分离,而不是从另一个继承。
如果没有对对象模型的充分理解(因此这实际上可能不适用于您的情况),似乎ISvdModel
不应该是接口定义的一部分。它看起来更像是一个实现细节,而不一定是您试图执行的契约的一部分。对我来说,将ISvdModel
(或IBiasSvdModel
)传递到实现类的构造函数中更有意义,而不是将其作为ISvdPredictor
接口的一部分。那么你根本不需要两个单独的接口定义,你只需要一个接口的两个实现。
你甚至可以更进一步;如果ISvdPredictor
和IBiasSvdPredictor
之间的唯一区别是一个使用ISvdModel
,另一个使用IBiasSvdModel
,那么您甚至不需要两个实现,只需一个,并且您将为每种情况传递正确的ISvdModel
实例。这是一种称为控制反转的设计模式,特别是使用依赖注入,它非常强大,可以在程序中实现更高级别的代码重用。