【问题标题】:Design Pattern in C# to reduce Code Duplication looping through Class ListsC# 中的设计模式以减少通过类列表循环的代码重复
【发布时间】:2020-05-05 18:01:50
【问题描述】:

我有一个媒体项目代表每个项目可以有多个来自不同用户的书签和 cmets。

当我来更新存储库时,我需要获取所有现有的评论和书签并附加新的 cmets 和书签,代码可以工作,但我想不出一种干净的方法来通用地执行此操作,这将减少重复,随着更多这样的领域的计划

  public class MapValues
    {
        private readonly string _userName;
        private readonly Media _media;
        private readonly IMediaRepository _mediaRepo;

        public MapValues(string userName, Media media, IMediaRepository mediaRepo)
        {
            _userName = userName;
            _media = media;
            IMediaRepository = mediaRepo;
        }

        public async Task<Media> AppendExistingUserValues(Media updatedMedia, string userName)
        {
            var existingMedia = await _mediaRepo.GetByIdAsync(updatedMedia.Id);
            var existingBookmarks = GetBookmarksExcludingUser(userName, existingMedia);
            var existingComments = GetCommentsExcludingUser(userName, existingMedia);

            if (updatedMedia.Bookmarks.Any())
            {
                existingBookmarks.AddRange(updatedMedia.Bookmarks);
            }

            if (updatedMedia.Comments.Any())
            {
                existingComments.AddRange(updatedMedia.Comments);
            }

            updatedMedia.Bookmarks = existingBookmarks;
            updatedMedia.Comments = existingComments;
            return updatedMedia;
        }


        private List<MediaBookmarks> GetBookmarksExcludingUser(string userName, Media media)
        {
            var exisitingBookmarks = new List<MediaBookmarks>();
            if (media?.Bookmarks != null)
            {
                exisitingBookmarks.AddRange(media.Bookmarks
                    .Where(x => !string.Equals(x.Name, userName, StringComparison.CurrentCultureIgnoreCase)).ToList());
            }

            return exisitingBookmarks;
        }

        private List<MediaComments> GetCommentsExcludingUser(string userName, Media media)
        {
            var exisitingComments = new List<MediaComments>();
            if (media?.Bookmarks != null)
            {
                exisitingComments.AddRange(media.Comments
                    .Where(x => !string.Equals(x.Name, userName, StringComparison.CurrentCultureIgnoreCase)).ToList());
            }

            return exisitingComments;
        }
    }

    public class Media
    {
        public IEnumerable<MediaBookmarks> Bookmarks { get; set; }

        public IEnumerable<MediaComments> Comments { get; set; }
        public string Id { get; set; }
    }

    public class MediaBookmarks
    {
        public string Name { get; set; }
    }

    public class MediaComments
    {
        public string Name { get; set; }
    }

【问题讨论】:

  • 你在说哪个重复?
  • @PavelAnikhouski 我认为他不喜欢重复的书签和 cmets
  • @FilipCordas 可以轻松内联成一行方法调用
  • @PavelAnikhouski 看起来不需要这样做。并且只想将新项目添加到 I Enumerable

标签: c# oop design-patterns


【解决方案1】:

如果您创建一个接口 (IMediaItem),那么您可以为每个特定的类(书签和评论)实现它。

public interface IMediaItem //This could even be a class if required
{
    public string Name { get; set; }
}

 public class MediaBookmarks : IMediaItem 
{
  public string Name { get; set; }
}

public class MediaComments : IMediaItem 
{
  public string Name { get; set; }
}

那么在你的GetBookmarksExcludingUserGetCommentsExcludingUser 可以合并成这样:

private List<IMediaItem> GetMediaItemExcludingUser(string userName, IEnumerable<IMediaItem> sourceList)
    {
        var existingItems = new List<IMediaItem>();
        if (sourceList != null)
        {
            existingItems.AddRange(sourceList
                .Where(x => !string.Equals(x.Name, userName, StringComparison.CurrentCultureIgnoreCase)).ToList());
        }

        return existingItems;
    }

像这样调用那个方法:

var existingBookmarks = GetMediaItemExcludingUser(userName, existingMedia?.Bookmarks).Cast<MediaBookmarks>();

【讨论】:

  • 我觉得最好用一个界面
  • @FilipCordas 是的,根据“真实”应用程序的外观,这可能是一条更好的路线。如果真的像示例代码一样简单,那我完全同意。
  • @FilipCordas 根据您的建议更新。
  • @MicroMan 可能值得给我的答案看一下,据我所知没有必要这样做。
【解决方案2】:

据我所知,这整件事可以重写为

 public async Task<Media> AppendExistingUserValues2(Media updatedMedia, string userName)
    {
        var existingMedia = await _mediaRepo.GetByIdAsync(updatedMedia.Id);


        updatedMedia.Bookmarks = updatedMedia.Bookmarks
            .Union(existingMedia.Bookmarks.Where(x => !string.Equals(x.Name, userName, StringComparison.CurrentCultureIgnoreCase))).ToList();

        updatedMedia.Comments = updatedMedia.Comments
            .Union(existingMedia.Comments.Where(x => !string.Equals(x.Name, userName, StringComparison.CurrentCultureIgnoreCase))).ToList();

        return updatedMedia;
    }

我还喜欢使用扩展器方法来使字符串 equals 更易读,所以使用助手。

public static class StringHelpers
    {
        public static bool IsSame(this string str1, string str2)
        {
            return string.Equals(str1, str2, StringComparison.CurrentCultureIgnoreCase);
        }
    }

你可以写。

public async Task<Media> AppendExistingUserValues2(Media updatedMedia, string userName)
        {
            var existingMedia = await _mediaRepo.GetByIdAsync(updatedMedia.Id);


            updatedMedia.Bookmarks = updatedMedia.Bookmarks
                .Union(existingMedia.Bookmarks.Where(x => x.Name.IsSame(userName))).ToList();

            updatedMedia.Comments = updatedMedia.Comments
                .Union(existingMedia.Comments.Where(x => x.Name.IsSame(userName))).ToList();

            return updatedMedia;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    • 2013-06-24
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    相关资源
    最近更新 更多