基于接口对象类型的方法偏差

时间:2018-08-06 05:20:29

标签: c# class interface

所以我读到要检查一个接口参数是不好的设计,因为在接口成员中发送应该与将要使用的唯一接口成员的契约相关联。因此,我认为只是简单地重载该方法。这似乎很快就会失去控制,但是如果实现该接口的多个对象需要该方法的不同实现。

class Operation(models.Model):
    ...
    # rest of fields
    worker = models.ForeignKey(Worker, related_name='operation')
    crypto = models.ForeignKey(Crypto, related_name='operation')

在上面的代码片段中,当我需要使用SpotifyArtist对象(实现IArtist)调用FindArtist时,该函数应查找具有相同名称和SpotifyID的对象。而如果它是其他任何类型的IArtist,则仅根据名称返回(可能会对其进行修改,以在以后优先处理非SpotifyArtist对象)。您对我应该在这里做什么有任何建议吗?

EDIT TableImplementation:

public IArtist FindArtist(IArtist artist)
        {
            var activeArtist = _database.Artists.FirstOrDefault(a => a.Name == artist.Name);
            return activeArtist;
        }
public IArtist FindArtist(SpotifyArtist artist)
        {
            var spotifyArtists = _database.Artists.Where(a => a is SpotifyArtist).Cast<SpotifyArtist>();
            SpotifyArtist activeArtist = spotifyArtists.FirstOrDefault(a => a.Name == artist.Name && a.SpotifyID == artist.SpotifyID);
            return activeArtist;
        }

3 个答案:

答案 0 :(得分:1)

好吧,这并不能直接回答您的问题,因为我认为可能有点XY。

但是,这就是id的作用,让关系数据成为关系数据。即使用关系数据库。

艺术家是一个关键概念,只有一个。制作一个Artists表。

一个 Artist 可能有多个 Spotify 帐户,因此我们可能需要一个Spotify表来保存网址,乐队名称,图片等内容……我表示一名 Artist 可以在多个频段内播放。因此,这里的解决方法是与 Artist 建立一对多关系以 Spotify

Youtube可能拥有相同的功能,一位艺术家可能拥有许多视频。再次一对多。

每当您需要添加更多连接(关系)时,您只需添加一个新表,就不必在一个表上进行扩展(您不必继续向艺术家表中添加与失败相关的垃圾),这是您唯一的选择需要添加(如果您想要的是导航集合属性)。

一个示例用法是以简单的伪代码方式

var artist = db.Include(x => x.SpotifyAccounts)
               .Include(x => x.YouTubeVideos)
               .Include(x => x.EbayStores)
               .FirstOrDefault(x => x.Name == SearchName); 

Console.WriteLine(artist.Name);
if(artist.SpotifyAccounts.Any)
   foreach(var item in artist.SpotifyAccounts)
       Console.WriteLine(" -- " + item.Url);

var spotify = db.SpotifyAccounts
                .Include(x => x.Arists)
                .FirstOrDefault(x => x.Id == SpotifyId);

Console.WriteLine(spotify.Id);
Console.WriteLine(spotify.Url);
Console.WriteLine(spotify.Artist.Name);

注意:这将消除您的搜索方法和继承,并替换为关系。不利之处是什么?嗯,不是每个表都在一个表中,继承实际上不是一种选择。优点是,随着模型变得越来越复杂,您只需添加关系即可,您可以添加任意数量的关系,实际上这并不会影响您的Artist表(除非它是一对一的)

搜索艺术家名称时,您可以访问他们拥有的所有内容。如果您搜索特定的 Spotify 帐户,则您始终可以访问 Artist

但是,这实际上取决于您想走多远的距离。如果这将是任何类型的系统,我认为关系式是必经之路。它具有可扩展性,自洽性以及大多数大型系统的工作方式

答案 1 :(得分:-1)

如果IArtist对于不同类型的行为不同,那将是不好的形式。如果实现不同,也可以在后台做不同的事情,那就可以了。如果将其视为黑匣子,则功能行为有所不同,则不正确。合同承诺了某些事情,应该保持一致。

如果您碰巧在知道有SpotifyArtist的地方编写代码,那么您也知道可以调用其他方法。

public IArtist FindArtistByName(IArtist artist)
{
    var activeArtist = _database.Artists.FirstOrDefault(a => a.Name == artist.Name);
    return activeArtist;
}

public IArtist FindArtistByNameAndID(SpotifyArtist artist)
{
    var spotifyArtists = _database.Artists.Where(a => a is SpotifyArtist).Cast<SpotifyArtist>();
    SpotifyArtist activeArtist = spotifyArtists.FirstOrDefault(a => a.Name == artist.Name && a.SpotifyID == artist.SpotifyID);
    return activeArtist;
}

您还可以提供一种便捷的方法:

public IArtist FindArtistByBestMethod(IArtist artist)
{
    if (artist is SpotifyArtist)
    {
        return repo.FindArtistByNameAndID((SpotifyArtist)artist);
    }
    else
    {
        return repo.FindArtistByName(artist);
    }
}

答案 2 :(得分:-1)

使用过滤器的答案:

过滤器:

public ArtistFilter
{
    public string SearchString { get; set; }
    public Type? Type { get; set; }
    public int? MinimumRating { get; set; }
}

MinimumRating只是为了向您展示如何轻松扩展过滤器。

第二个方法是将过滤器转换为函数:

private static Expression<Func<IArtist, bool>> CreateArtistFilterExpression(ArtistFilter filter)
{
    Expression<Func<IArtist, bool>> expression = x => true;
    if(filter == null)
    {
        return expression;
    }
    if(!string.IsNullOrWhiteSpace(filter.SearchString))
    {
        expression = expression.And(x => x.Name.Contains(filter.SearchString));
    }
    if(filter.Type != null)
    {
        expression = expression.And(x => x is Type.Value);
    }
    if(filter.MinimumRating != null)
    {
        expression = expression.And(x => x.Rating >= filter.MinimumRating);
    }
    return expression;
}

And-extension方法非常小:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) {
    var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
    return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}

最后一种方法可以减少冗余代码:

public List<IArtist> GetArtistsByFilter(ArtistFilter filter)
{
    var expression = CreateArtistFilterExpression(filter);
    return _database.Artists.Where(expression).ToList();
}

这样您可以获得最匹配的一个:

var filter = new ArtistFilter {
    SearchString = "Lennon",
    Type = typeof(SpotifyArtist)
};
var matchingArtists = GetArtistsByFilter(filter);
var bestMatching = matchingArtists.FirstOrDefault();

您将忽略该评级。通过同时设置MinimumRating,您还可以过滤出仅优秀艺术家。

注意:我在stackoverflow中输入了大部分内容,所以我可能会漏掉一个分号。