C# 需要一些关于我的软件架构的建议。[守则检讨]
我正在制作一个开源C#库,供其他开发人员使用。我最关心的是易用性。这意味着使用直观的名称、直观的方法使用等 这是我第一次考虑其他人,所以我非常关心架构的质量。另外,我不介意学一两件事 我有三门课: 下载程序、解析器和电影 我在想,最好只公开我的库的电影类,让下载程序和解析器保持隐藏状态,不被调用 最终,我看到我的库被这样使用 使用FreeIMDBC# 需要一些关于我的软件架构的建议。[守则检讨],c#,.net,architecture,C#,.net,Architecture,我正在制作一个开源C#库,供其他开发人员使用。我最关心的是易用性。这意味着使用直观的名称、直观的方法使用等 这是我第一次考虑其他人,所以我非常关心架构的质量。另外,我不介意学一两件事 我有三门课: 下载程序、解析器和电影 我在想,最好只公开我的库的电影类,让下载程序和解析器保持隐藏状态,不被调用 最终,我看到我的库被这样使用 使用FreeIMDB public void Test() { var MyMovie = Movie.FindMovie("The Matrix"); /
public void Test()
{
var MyMovie = Movie.FindMovie("The Matrix");
//Now MyMovie would have all it's fields set and ready for the big show.
}
你能回顾一下我是如何计划这件事的,并指出我做出的任何错误判断以及我可以改进的地方吗
记住,我主要关心的是易用性
Movie.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace FreeIMDB
{
public class Movie
{
public Image Poster { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Rating { get; set; }
public string Director { get; set; }
public List<string> Writers { get; set; }
public List<string> Genres { get; set; }
public string Tagline { get; set; }
public string Plot { get; set; }
public List<string> Cast { get; set; }
public string Runtime { get; set; }
public string Country { get; set; }
public string Language { get; set; }
public Movie FindMovie(string Title)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieTitle(Title);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
public Movie FindKnownMovie(string ID)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieID(ID);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
namespace FreeIMDB
{
/// <summary>
/// Provides a simple, and intuitive way for searching for movies and actors on IMDB.
/// </summary>
class Parser
{
private Downloader downloader = new Downloader();
private HtmlDocument Page;
#region "Page Loader Events"
private Parser()
{
}
public static Parser FromMovieTitle(string MovieTitle)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindMovie(MovieTitle);
return newParser;
}
public static Parser FromActorName(string ActorName)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindActor(ActorName);
return newParser;
}
public static Parser FromMovieID(string MovieID)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindKnownMovie(MovieID);
return newParser;
}
public static Parser FromActorID(string ActorID)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindKnownActor(ActorID);
return newParser;
}
#endregion
#region "Page Parsing Methods"
public string Poster()
{
//Logic to scrape the Poster URL from the Page element of this.
return null;
}
public string Title()
{
return null;
}
public DateTime ReleaseDate()
{
return null;
}
#endregion
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统图;
命名空间FreeIMDB
{
公映
{
公共图像海报{get;set;}
公共字符串标题{get;set;}
公共日期时间释放日期{get;set;}
公共字符串评级{get;set;}
公共字符串控制器{get;set;}
公共列表写入程序{get;set;}
公共列表类型{get;set;}
公共字符串标记行{get;set;}
公共字符串绘图{get;set;}
公共列表强制转换{get;set;}
公共字符串运行时{get;set;}
公共字符串国家{get;set;}
公共字符串语言{get;set;}
公共电影FindMovie(字符串标题)
{
电影=新电影();
Parser Parser=Parser.FromMovieTitle(标题);
film.Poster=parser.Poster();
film.Title=parser.Title();
film.ReleaseDate=解析器.ReleaseDate();
//等等。
}
公共电影FindKnownMovie(字符串ID)
{
电影=新电影();
Parser Parser=Parser.FromMovieID(ID);
film.Poster=parser.Poster();
film.Title=parser.Title();
film.ReleaseDate=解析器.ReleaseDate();
//等等。
}
}
}
Parser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace FreeIMDB
{
public class Movie
{
public Image Poster { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Rating { get; set; }
public string Director { get; set; }
public List<string> Writers { get; set; }
public List<string> Genres { get; set; }
public string Tagline { get; set; }
public string Plot { get; set; }
public List<string> Cast { get; set; }
public string Runtime { get; set; }
public string Country { get; set; }
public string Language { get; set; }
public Movie FindMovie(string Title)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieTitle(Title);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
public Movie FindKnownMovie(string ID)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieID(ID);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
namespace FreeIMDB
{
/// <summary>
/// Provides a simple, and intuitive way for searching for movies and actors on IMDB.
/// </summary>
class Parser
{
private Downloader downloader = new Downloader();
private HtmlDocument Page;
#region "Page Loader Events"
private Parser()
{
}
public static Parser FromMovieTitle(string MovieTitle)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindMovie(MovieTitle);
return newParser;
}
public static Parser FromActorName(string ActorName)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindActor(ActorName);
return newParser;
}
public static Parser FromMovieID(string MovieID)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindKnownMovie(MovieID);
return newParser;
}
public static Parser FromActorID(string ActorID)
{
var newParser = new Parser();
newParser.Page = newParser.downloader.FindKnownActor(ActorID);
return newParser;
}
#endregion
#region "Page Parsing Methods"
public string Poster()
{
//Logic to scrape the Poster URL from the Page element of this.
return null;
}
public string Title()
{
return null;
}
public DateTime ReleaseDate()
{
return null;
}
#endregion
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用HtmlAgilityPack;
命名空间FreeIMDB
{
///
///为在IMDB上搜索电影和演员提供了一种简单直观的方法。
///
类解析器
{
私有下载程序下载程序=新下载程序();
私有HtmlDocument页面;
#区域“页面加载程序事件”
专用解析器()
{
}
MovieTitle(stringmovietitle)的公共静态解析器
{
var newParser=newParser();
newParser.Page=newParser.downloader.FindMovie(MovieTitle);
返回newParser;
}
来自ActorName的公共静态解析器(字符串ActorName)
{
var newParser=newParser();
newParser.Page=newParser.downloader.FindActor(ActorName);
返回newParser;
}
公共静态解析器FromMovieID(字符串MovieID)
{
var newParser=newParser();
newParser.Page=newParser.downloader.FindKnownMovie(MovieID);
返回newParser;
}
来自ActorID的公共静态解析器(字符串ActorID)
{
var newParser=newParser();
newParser.Page=newParser.downloader.FindKnownActor(ActorID);
返回newParser;
}
#端区
#区域“页面解析方法”
公共字符串海报()
{
//从页面元素中删除海报URL的逻辑。
返回null;
}
公共字符串标题()
{
返回null;
}
公共日期时间发布日期()
{
返回null;
}
#端区
}
}
-----------------------------------------------
你们认为我正在朝着一条好的道路前进,还是我在为自己的未来设置一个充满伤害的世界
我最初的想法是将下载、解析和实际填充分离开来,以便轻松地拥有一个可扩展的库。想象一下,如果有一天网站更改了它的HTML,那么我只需修改解析类,而不必碰Downloader.cs或Movie.cs类
谢谢你的阅读和帮助
还有其他想法吗?我只会公开有意义的项目。对于您的代码,最终结果是电影信息。下载程序和解析器是无用的,除非用于获取电影信息,因此没有理由公开它们 同样,在你的电影课上,我只会让信息变得可获取,而不是太可设置。类没有“保存”功能,因此在获得信息后没有理由编辑信息 除此之外,如果这是针对其他人的,我会评论每个类、成员和每个公共/私有类变量的用途。对于电影类,我可能会在课堂评论中包括一个如何使用它的示例 最后一件事,如果两个私有类中存在错误,则需要以某种方式通知Movie类的用户。可能是一个名为success的公共bool变量 根据个人偏好,对于您的电影类,我希望您的两个函数都是构造函数,这样我就可以按如下方式构建该类 电影myMovie=新电影(“名称”); 或
电影myMovie=新电影(1245)这里有一些建议,没有什么大的,只是一些需要考虑的事情。
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...;
}
}
public class NeedsMovies
{
private readonly IMovieRepository _movies;
public NeedsMovies(IMovieRepository movies)
{
_movies = movies;
}
public void DoStuffWithMovie(string title)
{
var movie = _movies.FindMovieByTitle(title);
...
}
}
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...
}
// Data Contract (or Data Transfer Object)
public class Movie
{
public Image Poster { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Rating { get; set; }
public string Director { get; set; }
public List<string> Writers { get; set; }
public List<string> Genres { get; set; }
public string Tagline { get; set; }
public string Plot { get; set; }
public List<string> Cast { get; set; }
public string Runtime { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
// Movie database searching service contract
public interface IMovieSearchService
{
Movie FindMovie(string Title);
Movie FindKnownMovie(string ID);
}
// Movie database searching service
public partial class MovieSearchService: IMovieSearchService
{
public Movie FindMovie(string Title)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieTitle(Title);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
public Movie FindKnownMovie(string ID)
{
Movie film = new Movie();
Parser parser = Parser.FromMovieID(ID);
film.Poster = parser.Poster();
film.Title = parser.Title();
film.ReleaseDate = parser.ReleaseDate();
//And so an so forth.
}
}
public abstract class Parser
{
public abstract IEnumerable<Movie> Parse(string criteria);
}
public class ByTitleParser: Parser
{
public override IEnumerable<Movie> Parse(string title)
{
// TODO: Logic to parse movie information by title
// Likely to return one movie most of the time, but some movies from different eras may have the same title
}
}
public class ByActorParser: Parser
{
public override IEnumerable<Movie> Parse(string actor)
{
// TODO: Logic to parse movie information by actor
// This one can return more than one movie, as an actor may act in more than one movie
}
}
public class ByIdParser: Parser
{
public override IEnumerable<Movie> Parse(string id)
{
// TODO: Logic to parse movie information by id
// This one should only ever return a set of one movie, since it is by a unique key
}
}
public class ParserFactory
{
public virtual Parser GetParser(string criteriaType)
{
if (criteriaType == "bytitle") return new ByTitleParser();
else if (criteriaType == "byid") return new ByIdParser();
else throw new ArgumentException("Unknown criteria type.", "criteriaType");
}
}
// Improved movie database search service
public class MovieSearchService: IMovieSearchService
{
public MovieSearchService(ParserFactory parserFactory)
{
m_parserFactory = parserFactory;
}
private readonly ParserFactory m_parserFactory;
public Movie FindMovie(string Title)
{
var parser = m_parserFactory.GetParser("bytitle");
var movies = parser.Parse(Title); // Parse method creates an enumerable set of Movies that matched "Title"
var firstMatchingMovie = movies.FirstOrDefault();
return firstMatchingMovie;
}
public Movie FindKnownMovie(string ID)
{
var parser = m_parserFactory.GetParser("byid");
var movies = parser.Parse(Title); // Parse method creates an enumerable set of Movies that matched "ID"
var firstMatchingMovie = movies.FirstOrDefault();
return firstMatchingMovie;
}
}