Need some suggestions on my softwares architecture. [Code review]

后端 未结 4 1910
说谎
说谎 2021-02-09 10:38

I\'m making an open source C# library for other developers to use. My key concern is ease of use. This means using intuitive names, intuitive method usage and s

4条回答
  •  野趣味
    野趣味 (楼主)
    2021-02-09 10:52

    Your API is mostly static, meaning you are setting yourself up for maintainability issues in the future. This is because the static methods are actually singletons, which have some significant drawbacks.

    I suggest striving for a more instance-based, decoupled approach. This will naturally separate the definition of each operation from its implementation, leaving room for extensibility and configuration. An API's ease-of-use is measured not only by its public surface, but also by its adaptability.

    Here is how I would go about designing this system. First, define something which is responsible for fetching movies:

    public interface IMovieRepository
    {
        Movie FindMovieById(string id);
    
        Movie FindMovieByTitle(string title);
    }
    

    Next, define something which is responsible for downloading HTML documents:

    public interface IHtmlDownloader
    {
        HtmlDocument DownloadHtml(Uri uri);
    }
    

    Then, define a repository implementation which uses a downloader:

    public class MovieRepository : IMovieRepository
    {
        private readonly IHtmlDownloader _downloader;
    
        public MovieRepository(IHtmlDownloader downloader)
        {
            _downloader = downloader;
        }
    
        public Movie FindMovieById(string id)
        {
            var idUri = ...build URI...;
    
            var html = _downloader.DownloadHtml(idUri);
    
            return ...parse ID HTML...;
        }
    
        public Movie FindMovieByTitle(string title)
        {
            var titleUri = ...build URI...;
    
            var html = _downloader.DownloadHtml(titleUri);
    
            return ...parse title HTML...;
        }
    }
    

    Now, anywhere you need to download movies, you can depend solely on IMovieRepository without being directly coupled to all the implementation details beneath it:

    public class NeedsMovies
    {
        private readonly IMovieRepository _movies;
    
        public NeedsMovies(IMovieRepository movies)
        {
            _movies = movies;
        }
    
        public void DoStuffWithMovie(string title)
        {
            var movie = _movies.FindMovieByTitle(title);
    
            ...
        }
    }
    

    In addition, you can now easily test the parsing logic without having to make web calls. Simply save the HTML and create a downloader which gives it to a repository:

    public class TitleHtmlDownloader : IHtmlDownloader
    {
        public HtmlDocument DownloadHtml(Uri uri)
        {
            return ...create document from saved HTML...
        }
    }
    
    [Test]
    public void ParseTitle()
    {
        var movies = new MovieRepository(new TitleHtmlDownloader());
    
        var movie = movies.GetByTitle("The Matrix");
    
        Assert.AreEqual("The Matrix", movie.Title);
    
        ...assert other values from the HTML...
    }
    

提交回复
热议问题