最近维护一项目,是基于面向协议编程的。项目结束后,对面向协议编程有了更深刻的认识,特记录下。由于项目涉密问题,不便公开。只能以网络上例子来说明。
需求
项目的需求大致如此:一个动物园里,先来了一群动物(猫,老鹰和鲨鱼),要先把这些动物入系统库(写实现类);过了没有多久,又来进一批动物(海豚,鸵鸟和金鱼),要求新进动物按类目进行分类处理(这里主要强调实现类的变化)。
分析:
对于先进来的三类动物,最简单的实现就是按动物名称实现类。对于后进来的动物,就是在原来基础上进行扩展。强调的是对已有类的扩展。
我们先按面向对象编程实现一下.(毕竟现在面向对象是最普遍的方式)
import UIKit
/*
先定义一个基类(Animal),该基类有age和gender两个属性;eat和sleep两方法
*/
class Animal {
var age:Int {
return 0
}
var gender:Bool {
return false
}
func eat() {
print("Animal.. eat..")
}
func sleep() {
print("Animal.. sleep..")
}
}
/*
然后定义一个Cat类,继承Animal基类,重写Animal的属性和方法,同时有Cat自己的独特Func(catMethod)
*/
class Cat:Animal {
override var age:Int {
return 10
}
override var gender:Bool {
return true
}
override func eat() {
print("Cat.. eat..")
}
override func sleep() {
print("Cat.. sleep..")
}
func catMethod() {
print("Cat.. catMethod..")
}
}
//Eagle(老鹰)
class Eagle:Animal {
override var age:Int {
return 15
}
override var gender:Bool {
return false
}
override func eat() {
print("Eagle.. eat..")
}
override func sleep() {
print("Eagle.. sleep..")
}
func eagleMethod() {
print("Eagle.. eagleMethod..")
}
}
//Shark
class Shark:Animal {
override var age:Int {
return 2
}
override var gender:Bool {
return false
}
override func eat() {
print("Shark.. eat..")
}
override func sleep() {
print("Shark.. sleep..")
}
func sharkMethod() {
print("Shark.. sharkMethod..")
}
}
/*
至此,实现了开始的三个动物的实现类;然而对于后进来的三个动物,按需求要分类实现。那就是不能在原来实现类上修改了,只能新增加了。
新增加三个类目:哺乳动物类(FeedAnimals),鸟类(Birds)和鱼类(Fishs).并且都有自己的方法
*/
class FeedAnimals:Animal {
func Run() {
print("FeedAnimals.. Run..")
}
}
class Birds:Animal {
func Fly() {
print("Birds.. Fly..")
}
}
class Fishs:Animal {
func Swimming() {
print("Fishs.. Swimming..")
}
}
class FeedAnimalsAndBirds:Animal {
func Fly() {
print("BirdsAndFishd.. Fly..")
}
func Run() {
print("BirdsAndFishd.. Run..")
}
}
class FeedAnimalsAndFish:Animal {
func Run() {
print("FeedAnimalsAndBirds.. Run..")
}
func Swimming() {
print("FeedAnimalsAndBirds.. Swimming..")
}
}
//海豚属于动物,可以run,也可以swimming,所以继承Animal,FeedAnimals和Fishs
class Dolphin:FeedAnimalsAndFish {
override var age:Int {
return 3
}
override var gender:Bool {
return false
}
override func eat() {
print("Dolphin.. eat..")
}
override func sleep() {
print("Dolphin.. sleep..")
}
override func Run() { //重写FeedAnimals的方法
print("Dolphin.. Run..")
}
override func Swimming() { //重写Fish的方法
print("Dolphin.. Swimming..")
}
}
//鸵鸟,属于动物,可以run,所以继承Animal,FeedAnimals
class Ostrich:FeedAnimalsAndBirds {
override var age:Int {
return 3
}
override var gender:Bool {
return false
}
override func eat() {
print("Ostrich.. eat..")
}
override func sleep() {
print("Ostrich.. sleep..")
}
override func Run() { //重写FeedAnimals的方法
print("Ostrich.. Run..")
}
}
class Goldfish:Fishs {
override var age:Int {
return 3
}
override var gender:Bool {
return false
}
override func eat() {
print("Goldfish.. eat..")
}
override func sleep() {
print("Goldfish.. sleep..")
}
override func Swimming() { //重写Fish的方法
print("Goldfish.. Swimming..")
}
}
至此,使用面向对象方式,完成了按类目分类动物的实现方式。
但是完成这个需求,发现:
1.代码多。写了很多代码且又丑又长。
2.代码重复。很多代码都重复写了。
3.很多子类。派生好几个子类。
4.扩展性不好。开始三个类的代码不好改动,稍一改动,就会影响整个类。
改进
有没有更好方式呢?有的,我们试一下面向协议编程方式。
import UIKit
/*
首先定义一个AnimalProtocol协议,该协议有可选的age和gender属性;也有可选的eat和sleep方法。
至于可选方式,我这边使用的是 @objc,当然也可以使用extension来实现可选方式。
*/
@objc public Protocol AnimalProtocol {
@objc var age:Int {}
@objc var gender:Bool {}
@objc func eat() {}
@objc func sleep() {}
}
/*
生成一个Cat类,并继承AnimalProtocol协议,对于方法也可以可选择的实现
*/
class Cat:AnimalProtocol {
var age:Int {
return 2
}
func eat() {
print("Cat..eat..")
}
func sleep() {
print("Cat..sleep..")
}
}
/*
生成一个Eagle类,并继承AnimalProtocol协议,可选实现eat和sleep()
*/
class Eagle:AnimalProtocol {
func eat() {
print("Eagle..eat..")
}
func sleep() {
print("Eagle..sleep..")
}
}
//Shark,同样是可选实现
class Shark:AnimalProtocol {
var age:Int {
return 4
}
func eat() {
print("Shark..eat..")
}
func sleep() {
print("Shark..sleep..")
}
}
/*
对于新的类目FeedAnimals,Brids和Fishs,它们的实现方法就是run,fly和Swimming,
这里就不对类目进行实现,而是对其能力进行实现.分别定义runable,flyable和swimmingable的能力
*/
@objc public Protocol Runable {
@objc func run() {}
}
@objc public Protocol Flyable {
@objc func fly() {}
}
@objc public Protocol Swimmingable {
@objc func swimming() {}
}
/*
对于新增加的三个动物,就可以分别继承对应的协议了(协议是可以多继承的)
*/
/*
Dolphin具有Animal的能力,同时具有Run 和Swimming的能力
*/
class Dolphin:AnimalProtocol,Runable,Swimmingable {
var age:Int {
return 4
}
var gender:Bool {
return false
}
func eat() {
print("Dolphin..eat..")
}
func sleep() {
print("Dolphin..sleep..")
}
func run() {
print("Dolphin..run..")
}
func swimming() {
print("Dolphin..swimming..")
}
}
/*
Ostrich具有Animal和Run的能力
*/
class Ostrich:AnimalProtocol,Runable {
func eat() {
print("Ostrich..eat..")
}
func sleep() {
print("Ostrich..sleep..")
}
func run() {
print("Ostrich..run..")
}
}
class Goldfish:AnimalProtocol,Swimmingable {
func eat() {
print("Goldfish..eat..")
}
func swimming() {
print("Goldfish..swimming..")
}
}
敲完代码,发现面向协议编程确实比面向对象编程好多啦,具体为:
1.代码量少了很多。
2.协议支持多重继承。减少了子类。
3.协议支持可选。减少没有必要实现的方法或属性。
4.扩展性好多了。对于之前以后写好的类,直接继承新的协议接口,就可以新增加功能了,不会影响到原来的方法或属性,满足开闭原则。