C#中的继承问题

时间:2011-08-18 15:27:17

标签: c# inheritance refactoring

我正在重构一些代码,并希望继承链中的类更高一些,对它们的参数要严格一些。由于我不确定我是否正确解释了这一点,这就是我所拥有的:

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的论文编写这段代码。

6 个答案:

答案 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个单一接口的实现。

你甚至可以更进一步;如果ISvdPredictorIBiasSvdPredictor之间的唯一区别是使用ISvdModel而另一个使用IBiasSvdModel,那么您甚至不需要2个实现,只需要一个,你会为每种情况传递ISvdModel的正确实例。这是一种名为Inversion of Control的设计模式,特别是使用依赖注入,并且非常强大,可以在程序中实现更高级别的代码重用。