六大设计原则:单一职责原则

1,463 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金

最近在学习六大设计原则,醍醐灌顶,现在把自己的感受简单记录一下。

定义

单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。

通俗点说,也就是一个类只负责一种职责的工作,不存在多个原因使得一个类发生变化。

优点

  • 类的复杂度降低,一个类只负责一个功能,其逻辑要比负责多项功能简单的多;
  • 类的可读性增强,阅读起来轻松;
  • 可维护性强,一个易读、简单的类自然也容易维护;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

例子

这里就拿1个出名游戏做一下例子,如有雷同,纯属巧合哈。假设每一个召唤师,都可以拥有3个英雄,这时候我们可以定义一个Role的类,写上getheros方法

代码如下:

class Role {
    
    func getheros() -> [String] {
        return ["亚瑟", "后裔", "妲己"]
    }

}

这很简单是吧,这时候产品过来说,需求要变更了,加1个vip和平民的2种角色,vip1~vip7要多1个英雄。vip8以后,要多2个英雄。

好,这时候我们直接弄一个枚举来定义角色,用swit遍历枚举来返回英雄。

代码如下:

enum IDE {
    case vip(Int)
    case pingmin
}

class Role {
    
    func getheros(ide: IDE) -> [String] {
        switch ide {
        case let .vip(number):
            if (number >= 8) {
                return ["亚瑟", "后裔", "妲己", "赵云", "武则天"]
            }else {
                return ["亚瑟", "后裔", "妲己", "赵云"]
            }
        case .pingmin:
            return ["亚瑟", "后裔", "妲己"]
        }
    }
}

这么看,也不是很难是吧。

随着需求的迭代,这时候产品有说,角色添加打架功能,平民一开始战斗力为0,vip1~vip7为10,vip8以后为20。

这时候,其实我们感觉有点不对劲了,但在原来基础上好像也不是改动很大,好,再改

class Role {
    
    func getheros(ide: IDE) -> [String] {
        switch ide {
        case let .vip(number):
            if (number >= 8) {
                return ["亚瑟", "后裔", "妲己", "赵云", "武则天"]
            }else {
                return ["亚瑟", "后裔", "妲己", "赵云"]
            }
        case .pingmin:
            return ["亚瑟", "后裔", "妲己"]
        }
    }
    
    func fight(ide: IDE) -> Int {
        switch ide {
        case let .vip(number):
            if (number >= 8) {
                return 20
            }else {
                return 10
            }
        case .pingmin:
            return 0
        }
    }
}

这时候,产品的需求,又TM增加了,vip的角色拥有显示皮肤功能,而且vip8以后的才可以有建群功能。

如果在这上面代码基础下,是不是又要添加两个方法,再枚举遍历去输出相应的内容。这时候我们已经意识到Role这个类越来越臃肿了,那后面产品再改动或者增加,感觉就不好维护了。

单一职责原则是说一个类只负责一种职责的工作,很明显这里Role类,已经负责很多种职责了。平民有3个英雄,vip1~vip7有4个英雄,vip8后面有5个英雄,这才是单一职责原则,而不是角色拥有3或4或5个英雄。

好,那我们就可以建一个类为pinmin,1个类是vip1,vip2...,每个身份都拥有自己的功能。

class pingmin: Role {
    override func getheros() -> [String] {
        return ["亚瑟", "后裔", "妲己"]
    }
    
    override func fight() -> Int {
        return 0
    }
}

class Vip1: Role {
    
    override func getheros() -> [String] {
        return ["亚瑟", "后裔", "妲己", "赵云"]
    }
    
    override func fight() -> Int {
        return 10
    }
    
    func showPiFu() {
        print("显示皮肤")
    }
}

class Vip8: Role {
    
    override func getheros() -> [String] {
        return ["亚瑟", "后裔", "妲己", "赵云", "武则天"]
    }
    
    override func fight() -> Int {
        return 20
    }
    
    func havaPiFu() {
        print("显示皮肤")
    }
    
    func createGroup() {
        print("建群")
    }
}

那后面,如果哪种身份又需要添加功能,我们就可以直接在该类上添加即可,这样就完全不会影响到其它类,耦合度也大大降低了,代码也不会全部臃肿在1个类当中。

总结

单一职责原则是六大设计原则中算是比较简单的了,但管中窥豹,实际开发中,随着功能的增多,要及时注意,看是否有违背一个类只负责一种职责的工作,能重构就马上重构,不然代码量多了后,想重构又难,继续有原来基础上维护又难。

如果以上说法有不足之处,欢迎留意。