决定如何重构具有多种方法的 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 至少担任以下角色:
- 维护对象集合(您的"local database")
- 读取from/writing到云服务器
- 正在将云服务器数据转换为您的模型 class 个对象
- 保持本地数据库与云数据库双向同步。
- 定义您的业务对象模型(用户、地点、子优先级等)。
- 协调以上所有内容。
如果我要实现这个,我会将 1-4 分成单独的 classes。对于 #5,我会将模型移出后端,因此它们是独立的 classes.
- 维护对象集合(您的"local database")
数据存储属于自己 class。对于所有对象类型,这已经相当复杂了。
- 读取from/writing到云服务器
任何访问外部资源的代码都属于它自己的 class,它只进行数据访问。理想情况下,这个 class 应该首先定义为一个接口,调用者应该只通过接口调用它。这使得交换提供者更容易,也有助于测试(您可以在运行时为测试提供不同的 DAL 实现)并加强关注点分离。
正在将云服务器数据转换为您的模型 class 个对象
这可以在 DAL 或中间层中完成。要下载云数据,您可以将方法添加到您的集合 classes,例如
LocalDatabase.Users.Update(列表<User
> usersFromCloud){}
- 保持本地数据库与云数据库双向同步。
位于后端、云 DAL 和本地数据库之间的中间 class 可以同步 "automatically" 只要它知道一侧的数据已经过时。或者,这可以移动到实用程序 class。哪个最好取决于您的要求。
- 定义您的业务对象模型(用户、地点、子优先级等)。
后端之外的代码正在使用这些模型,因此它们属于后端定义之外。
- 协调以上所有内容。
当您删除上面列出的所有内容时,剩下的将是一堆对新 classes 的方法调用来完成所有工作。您的后端 class 将更像是一个协调员,将工作委托给适当的 class。
我会做的其他事情
使用非静态 classes. 如果您打算使用一个全局对象来提供对后端的访问,则可以使用单例。 (例如 Google "C# singleton"。)。这将使您更容易测试您的代码(通过换出您存储在单例中的内容,例如使用文本文件中的 returns 值的虚拟实现)并且如果以后更容易切换到非全局实现变得有必要。
我注意到,与我倾向于在线阅读的代码相比,我的 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 至少担任以下角色:
- 维护对象集合(您的"local database")
- 读取from/writing到云服务器
- 正在将云服务器数据转换为您的模型 class 个对象
- 保持本地数据库与云数据库双向同步。
- 定义您的业务对象模型(用户、地点、子优先级等)。
- 协调以上所有内容。
如果我要实现这个,我会将 1-4 分成单独的 classes。对于 #5,我会将模型移出后端,因此它们是独立的 classes.
- 维护对象集合(您的"local database") 数据存储属于自己 class。对于所有对象类型,这已经相当复杂了。
- 读取from/writing到云服务器 任何访问外部资源的代码都属于它自己的 class,它只进行数据访问。理想情况下,这个 class 应该首先定义为一个接口,调用者应该只通过接口调用它。这使得交换提供者更容易,也有助于测试(您可以在运行时为测试提供不同的 DAL 实现)并加强关注点分离。
正在将云服务器数据转换为您的模型 class 个对象 这可以在 DAL 或中间层中完成。要下载云数据,您可以将方法添加到您的集合 classes,例如
LocalDatabase.Users.Update(列表
<User
> usersFromCloud){}
- 保持本地数据库与云数据库双向同步。 位于后端、云 DAL 和本地数据库之间的中间 class 可以同步 "automatically" 只要它知道一侧的数据已经过时。或者,这可以移动到实用程序 class。哪个最好取决于您的要求。
- 定义您的业务对象模型(用户、地点、子优先级等)。 后端之外的代码正在使用这些模型,因此它们属于后端定义之外。
- 协调以上所有内容。 当您删除上面列出的所有内容时,剩下的将是一堆对新 classes 的方法调用来完成所有工作。您的后端 class 将更像是一个协调员,将工作委托给适当的 class。
我会做的其他事情
使用非静态 classes. 如果您打算使用一个全局对象来提供对后端的访问,则可以使用单例。 (例如 Google "C# singleton"。)。这将使您更容易测试您的代码(通过换出您存储在单例中的内容,例如使用文本文件中的 returns 值的虚拟实现)并且如果以后更容易切换到非全局实现变得有必要。