决定如何重构具有多种方法的 class

Deciding how to refactor a class having many methods

我注意到,与我倾向于在线阅读的代码相比,我的 classes 往往是 larger/longer。下面的代码只是一个例子,但我更感兴趣的是思考问题的方式和解决问题的方式。

如您所见,class 担当许多角色,我很想了解如何将其重构为其他 classes 和示例,如果可能的话,关于实际解决方案。关于如何解决此问题的指向 books/guides 的链接会很棒。

所以我有一个带有以下声明的后端 class。我正在使用 C#,但我认为我的问题涉及其他语言。

public static class Backend {
    //These classes are the equivalent classes of a cloud database tables
    //Using them to map the tables to objects in my app
    public class User{}
    public class Place{}
    public class SubPriority{}
    public class Question{}
    public class Parent{}
    public class Response{}
    public class SubParent{}

    //initialize the local and cloud databases
    public static async void init();

    //Add place to local database
    public static string AddPlace(string name, string buildingType)

    //Retrieve places from local database
    public static List<Place> RetrievePlaces()

    //Delete a place from local database
    public static bool DeletePlace(string placeID)

    public static string AddSubPriority(String name)
    public static List<SubPriority> RetrieveSubPriorities()
    public static bool DeleteSubPriority(string placeID, int ID)

    //Sync local db with cloud
    public static async Task<bool> SyncWithCloud()

    //Download SubParents from the cloud
    public static async Task<List<SubParent>> DownloadSubParents()

    //Retrieve SubParents from local
    public static List<SubParent> RetrieveSubParents(int parentid)
    ...
    ...
    ...
    //Similar methods for parents and questions



    //Handling login
    public static async Task<bool> Login(string userName, string pass)
    static async Task<bool> LoginOnline(string userName, string pass)
    static bool LoginOffline(string userName, string pass)

    //Check for internet connectivity
    static async Task<bool> isConnectedToInternet()
    static bool InternetAvailable()
}

关注点分离

将所有这些逻辑集中在一个 class 中的困难在于,更改一件事可能需要对整个 class 进行重大更改,这会产生错误。同样重要的是,当 classes 承担单一角色时更容易阅读和理解。可读的代码总是有更少的错误(根据我的经验)。

您的单身 class 至少担任以下角色:

  1. 维护对象集合(您的"local database")
  2. 读取from/writing到云服务器
  3. 正在将云服务器数据转换为您的模型 class 个对象
  4. 保持本地数据库与云数据库双向同步。
  5. 定义您的业务对象模型(用户、地点、子优先级等)。
  6. 协调以上所有内容。

如果我要实现这个,我会将 1-4 分成单独的 classes。对于 #5,我会将模型移出后端,因此它们是独立的 classes.


  1. 维护对象集合(您的"local database") 数据存储属于自己 class。对于所有对象类型,这已经相当复杂了。

  1. 读取from/writing到云服务器 任何访问外部资源的代码都属于它自己的 class,它只进行数据访问。理想情况下,这个 class 应该首先定义为一个接口,调用者应该只通过接口调用它。这使得交换提供者更容易,也有助于测试(您可以在运行时为测试提供不同的 DAL 实现)并加强关注点分离。

  1. 正在将云服务器数据转换为您的模型 class 个对象 这可以在 DAL 或中间层中完成。要下载云数据,您可以将方法添加到您的集合 classes,例如

    LocalDatabase.Users.Update(列表<User> usersFromCloud){}


  1. 保持本地数据库与云数据库双向同步。 位于后端、云 DAL 和本地数据库之间的中间 class 可以同步 "automatically" 只要它知道一侧的数据已经过时。或者,这可以移动到实用程序 class。哪个最好取决于您的要求。

  1. 定义您的业务对象模型(用户、地点、子优先级等)。 后端之外的代码正在使用这些模型,因此它们属于后端定义之外。

  1. 协调以上所有内容。 当您删除上面列出的所有内容时,剩下的将是一堆对新 classes 的方法调用来完成所有工作。您的后端 class 将更像是一个协调员,将工作委托给适当的 class。

我会做的其他事情

使用非静态 classes. 如果您打算使用一个全局对象来提供对后端的访问,则可以使用单例。 (例如 Google "C# singleton"。)。这将使您更容易测试您的代码(通过换出您存储在单例中的内容,例如使用文本文件中的 returns 值的虚拟实现)并且如果以后更容易切换到非全局实现变得有必要。