小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
最近在学习六大设计原则,醍醐灌顶,现在把自己的感受简单记录一下。
定义
开闭原则 (The Open/Closed Principle, OCP) 规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”[1],这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。
简单来说就是一个软件实体(如类、模块、函数)应当对扩展开放,对修改关闭。重点就是抽象化。
优点
-
抽象灵活性好,适应性广,基本保持软件架构的稳定
-
提高了复用性,以及可维护性
例子
这次的例子就弄简单一点,猫有吃的功能,并且我们用一个行动管理工具来管理。
class Cat {
func eat() -> String {
return "吃鱼"
}
}
class ActionManager {
func catEat(cat: Cat) {
print(cat.eat())
}
}
这里调用这个catEat方法
var action = ActionManager()
var cat = Cat()
action.catEat(cat: cat)
自然就输出“吃鱼”,这个自然没什么问题。
好了,产品过来说添加需求了,狗也要吃,吃狗粮。
那我们又建一个Dog的类,也添加eat方法,ActionManager也添加一个dogEat的方法。
class Dog {
func eat() -> String {
return "吃狗粮"
}
}
class ActionManager {
func catEat(cat: Cat) {
print(cat.eat())
}
func dogEat(dog: Dog) {
print(dog.eat())
}
}
我们直接调取dogEat方法
var action = ActionManager()
var dog = Dog()
action.dogEat(dog: dog)
自然也是输出“狗粮”,很明显,也是能解决产品的需求。
但是,这个就违背了开闭原则了,如果我们还有其它的猪,兔,猴子等也需要吃,那我们每次都要在ActionManager去添加方法,这样就每次都要改动这个类,这明显不是我们想要的效果。
开闭原则是核心是抽象化,好,那我们可以建一个抽象类,让ActionManger来调取抽象类即好,有什么其它动物,我们都继承抽象类,相当于扩展开放,这样后面如果不仅吃的,还有其它通用的,都可以写在抽象类中。
class Animal {
func eat() -> String {
return "吃肉"
}
}
class Cat: Animal {
override func eat() -> String {
return "吃鱼"
}
}
class Dog: Animal {
override func eat() -> String {
return "吃狗粮"
}
}
我们的ActionManger也可以写成
class ActionManager {
func eat(animal: Animal) {
print(animal.eat())
}
}
这时候,我们的调用就变成
var action = ActionManager()
var cat = Cat()
action.eat(animal: cat)
var dog = Dog()
action.eat(animal: dog)
相当于效果就是有1个碗是给动物吃的,但我们不知道是哪个动物吃,ActionManger对外提供就是你哪个动物过来吃,我就给你eat()的方法。
这么写法,我们是不是就提高了复用性和维护性了呢。
总结
当应用的需求改变时,在不修改软件实体包括类,模块,接口等的前提下,可以对其进行扩展的功能,使其满足新的需求。这就是开闭原则。
如果以上说法有不足之处,欢迎留意。