在基于 class 的环境中分离 Concerns/Code 结构(以 C# 为例)
Separation of Concerns/Code Structuring in a class based environment (C# used as example)
我一直想知道在基于 class 的语言中分离代码的最佳做法是什么。例如,我创建了一个项目来处理 api 与我的网络 api 的交互。我想知道正确的选择是什么,或者其他建议。
示例 1
项目文件
- Api.cs
- 数据类型
- Anime.cs
- Episode.cs
Api.cs
public class Api
{
public static async Task<List<Anime>> GetAnimesByKeyword(string keyword)
{
// Execute api request to server
return result;
}
public static async Task<List<Episode>> GetEpisodesByAnime(Anime anime)
{
// Execute api request to server
return result;
}
}
数据类型 -> Anime.cs
public class Anime
{
public string Name { get; set; }
public string Summary { get; set; }
// Other properties
}
数据类型 -> Episode.cs
public class Episode
{
public string Name { get; set; }
public Date ReleaseDate { get; set; }
// Other properties
}
或示例 2
项目文件
- Api.cs
- 数据类型
- Anime.cs
- Episode.cs
Api.cs
public class Api
{
// Nothing for now
}
数据类型 -> Anime.cs
public class Anime
{
public static async Task<Anime> GetById(int id)
{
return result;
}
public string Name { get; set; }
public string Summary { get; set; }
// Other properties
}
数据类型 -> Episode.cs
public class Episode
{
public static async Task<List<Episode>> GetEpisodesByAnime(Anime anime)
{
return result;
}
public string Name { get; set; }
public Date ReleaseDate { get; set; }
// Other properties
}
这两种结构代码的首选方式是什么,或者是否有更好的方式来做到这一点。这可能看起来微不足道,但对我来说很重要。
谢谢你帮我!
一般来说,遵循Single Responsibility Principle。实际上,这意味着您拥有仅包含数据的简单对象和更复杂的服务 class,它们的工作方式类似于从外部服务或数据库加载。
您的第二个示例混合了关注点并且它将这两个 class 紧密地绑定在一起(Episode
现在取决于 Anime
)。您还可以看到很难决定将加载方法放在哪个 class 上:应该是 anime.GetEpisodes()
还是 Episode.GetEpisodesByAnime()
?随着对象图变得越来越复杂,这种情况也会升级。
稍后您可能需要一个不同的实体数据传输对象。拥有简单的纯数据对象可以轻松添加这些对象并使用 Automapper
进行转换。
但是(在您的第一个示例中)不要使用 static
方法,因为这会使您的服务 class 更难测试。一项服务可能依赖于另一项服务(使用依赖注入),并且要单独测试每项服务,您不希望使用静态方法。
我一直想知道在基于 class 的语言中分离代码的最佳做法是什么。例如,我创建了一个项目来处理 api 与我的网络 api 的交互。我想知道正确的选择是什么,或者其他建议。
示例 1
项目文件
- Api.cs
- 数据类型
- Anime.cs
- Episode.cs
Api.cs
public class Api
{
public static async Task<List<Anime>> GetAnimesByKeyword(string keyword)
{
// Execute api request to server
return result;
}
public static async Task<List<Episode>> GetEpisodesByAnime(Anime anime)
{
// Execute api request to server
return result;
}
}
数据类型 -> Anime.cs
public class Anime
{
public string Name { get; set; }
public string Summary { get; set; }
// Other properties
}
数据类型 -> Episode.cs
public class Episode
{
public string Name { get; set; }
public Date ReleaseDate { get; set; }
// Other properties
}
或示例 2
项目文件
- Api.cs
- 数据类型
- Anime.cs
- Episode.cs
Api.cs
public class Api
{
// Nothing for now
}
数据类型 -> Anime.cs
public class Anime
{
public static async Task<Anime> GetById(int id)
{
return result;
}
public string Name { get; set; }
public string Summary { get; set; }
// Other properties
}
数据类型 -> Episode.cs
public class Episode
{
public static async Task<List<Episode>> GetEpisodesByAnime(Anime anime)
{
return result;
}
public string Name { get; set; }
public Date ReleaseDate { get; set; }
// Other properties
}
这两种结构代码的首选方式是什么,或者是否有更好的方式来做到这一点。这可能看起来微不足道,但对我来说很重要。
谢谢你帮我!
一般来说,遵循Single Responsibility Principle。实际上,这意味着您拥有仅包含数据的简单对象和更复杂的服务 class,它们的工作方式类似于从外部服务或数据库加载。
您的第二个示例混合了关注点并且它将这两个 class 紧密地绑定在一起(Episode
现在取决于 Anime
)。您还可以看到很难决定将加载方法放在哪个 class 上:应该是 anime.GetEpisodes()
还是 Episode.GetEpisodesByAnime()
?随着对象图变得越来越复杂,这种情况也会升级。
稍后您可能需要一个不同的实体数据传输对象。拥有简单的纯数据对象可以轻松添加这些对象并使用 Automapper
进行转换。
但是(在您的第一个示例中)不要使用 static
方法,因为这会使您的服务 class 更难测试。一项服务可能依赖于另一项服务(使用依赖注入),并且要单独测试每项服务,您不希望使用静态方法。