文章详情
面向协议编程依赖什么原则(与面向对象编程的异同点)
面向协议编程依赖什么原则(与面向对象编程的异同点)你知道“God Class”(全能类)是什么吗?就是在巨大的文件里,有一个类充满了各种分类、方法和变量。你的App里极有可能就有一些这样的“God Class”(全能类),甚至你自己都不知道。你知道“God Class”(全能类)是什么了吗?你感觉到它会对你的代码库造成毁灭性的影响了吗?往下看,我会告诉你怎么解决这些问题。
“God Class”(全能类)到底是什么?
一般来说,它存在于你的ViewController里,如果你使用的是MVC编程模式的话;如果你使用MVVM,则会在你的ViewModel里。让我来看一个MVVM编程模式下,“God Class”(全能类)的经典例子。
我们假设你正在构建一个约会App,你可能会需要一个UserViewModel来存储相关数据和处理业务逻辑
struct User { let id: UUID var name: String? var phone: String? var email: String? } class UserViewModel { private(set) var user: User? init(id: String) { self.user = fetchUser(with: id) } func fetchUser(with id: String) -> User? { //fetch user data from the CoreData and optionally return a User object } func verifyPhone() { if let phone = user?.phone { // Perform phone number verification } } func verifyEmail() { if let email = user?.email { // Perform email verification } } func update(name: String) { user?.name = name } func update(email: String) { user?.email = email verifyEmail() } }
内容非常直接了当:
- 这个类有一个User对象;
- 有一个初始化方法init(id: String);
- 有一个func fetchUser(with id: String) -> User?方法,用来从数据库读取用户信息;
- 有两个验证方法verifyPhone和verifyEmail用来验证用户信息;
- 有两个更新方法update(name: String)和update(email: String)用来更新用户的信息。
如你所见,这个类有三种业务逻辑,混杂在一个类里:
- 读取信息
- 验证信息
- 更新信息
甚至还会有更多复杂的业务逻辑。
这是一个典型的“God Class”(全能类),因为它什么都干。随着工程的不断迭代,“God Class”(全能类)很快就会变得十分臃肿巨大。
接下来,让我们看看面相协议编程能够怎样分解这些逻辑。
面向协议编程到底是什么?
根据Swift documentation的定义:
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol.
协议定义了实现一个功能或者特定任务所需的方法、属性以及其它一些必须条件的蓝图。协议能够被类、结构体,以及枚举类型继承,并提供、实现这些必须的条件。任意满足这些协议必须条件的类型就被称之为遵守这个协议。
命名规则
建议使用形容词来命名协议,通常采用后缀ble或者ing。
创建以协议为基础的分类和方法
1. UserIdentifiable
// Identify User protocol UserIdentifiable { var user: User? init(id: String) }复制代码// Identify User protocol UserIdentifiable { var user: User? init(id: String) }
这个协议包含一个user对象和一个init(id: String)初始化方法。
2. UserFetchable
// Fetch data from the database protocol UserFetchable { func fetchUser(with id: String) -> User? }
这个协议有一个方法fetchUser(with id: String)用来返回可选User类型对象。
3. UserVerifiable
// Verify user info protocol UserVerifiable { func verifyPhone() func verifyEmail() }
这个协议包含两个验证方法:verifyPhone和verifyEmail。
4. UserUpdatable
// Update user info protocol UserUpdatable { mutating func update(name: String) mutating func update(email: String) }
这个协议包含两个更新方法:update(name: String)和update(email: String)。因为我们会更新其它协议里定义的值,所以我们需要mutating关键字来修饰这些方法。
用协议来拆解这个“God Class”(全能类)
注意: 协议可以继承其它的协议以此来获取访问其属性和方法的能力。
实现协议
我们可以简单的在协议下方写一个扩展来实现fetchUser方法
protocol UserFetchable { func fetchUser(with id: String) -> User? } extension UserFetchable { func fetchUser(with id: String) -> User? { //fetch user data from the CoreData and optionally return a User object } }
对于UserVerifiable协议,因为我们需要使用User对象来取得用户信息,所以我们需要继承UserIdentifiable协议。
protocol UserVerifiable: UserIdentifiable { func verifyPhone() func verifyEmail() } extension UserVerifiable { func verifyPhone() { if let phone = user?.phone { // Perform phone number verification } } func verifyEmail() { if let email = user?.email { // Perform email verification } } }
实现UserUpdatable协议时也一样,因为我们需要调用UserVerifiable协议定义的verifyEmail方法,所以我们需要继承UserVerifiable协议。因为UserVerifiable已经继承了UserIdentifiable,所以UserUpdatable可以访问用户信息。
protocol UserUpdatable: UserVerifiable { mutating func update(name: String) mutating func update(email: String) } extension UserUpdatable { mutating func update(name: String) { user?.name = name } mutating func update(email: String) { user?.email = email verifyEmail() } }
这样我们基本上就完成了。最后,我们让UserViewModel继承于UserFetchable和UserUpdatable。 由于我们还没有实现UserIdentifiable协议,而且,把初始化方法放在类定义中也是好的做法。 所以,我们这样实现
struct User { let id: UUID var name: String? var phone: String? var email: String? } class UserViewModel: UserFetchable, UserUpdatable { var user: User? required init(id: String) { self.user = fetchUser(with: id) } }
总结
经过以上所有的重构之后,UserViewModel变得更加清晰了。所有的方法和属性都按照他们的功能进行了对应的分组。如果你想要添加,删除或者更新这些方法和属性,你只需要直接去协议中进行修改。
下一文章:仿抖音点赞效果实现方法(抖音点赞特效)
相关推荐
- 11-11米酷cms代审记录
- 10-21CVE-2020-15148Yii2反序列化RCEPOP链分析
- 10-21深入挖掘.NET注入
- 10-21初识MSF后门技术
- 10-21通过UAFbypassPHPdisabledfunctions
- 10-21fastadmin后台注入分析
- 10-28水水的记录某微两处SQL注入
- 11-16CVE-2020-25291:金山WPSOffice远程堆损坏漏
- 10-21ApacheSolrReplicationHandler漏洞浅析(CVE
- 10-21记一次众测找源码到RCE
- 11-02从Weblogic原理上探究CVE-2015-4852、CVE-2
- 10-27记一次红队经历
- 05-10某CMS代码审计思路分享
- 05-08分析和学习WordPress