设计模式是什么
程序员为了编写出,优雅,可读性强,高内聚低耦合的代码。为了实现这一目标,使出浑身解数,总结出来了一套编码的经验,这些经验就是设计模式。
所以说设计模式是一种经验,是一种针对某种业务模型的编码经验,设计模式是一种经验。
从另一个角度,也可以说设计模式是概念模型,举个例子,生产者消费者模式,会有生产者角色,会有消费者角色,有消息角色,角色之间的关系是什么样的。
正因为,设计模式,是经验,是模型,而不是某一个具体的定型,所以不同开发人员的实现方式是可以不一致的。
设计模式一般遵循六大设计原则,也可以这样说说,如果你可以遵循六大设计原则,总结出自己在某个业务场景下的编码经验,你就创造了设计模式。
单一职责原则
如果需要开发的一个功能需求不是一次性的,且随着业务发展的不断变化而变化,那么当一个Class类负责超过两个及以上的职责时,就在需求的不断迭代、实现类持续扩张的情况下,就会出现难以维护、不好扩展、测试难度大和上线风险高等问题。
所谓的职责就是指类变化的原因,也就是业务需求。如果一个类有多于一个的原因被改变,那么这个类就有超过两个及以上的职责。而单一职责约定一个类应该有且仅有一个改变类的原因。
定义class类 定义公共抽象接口,根据抽象接口使用不同的类实现,比如,视屏网站,普通用户,会员用户,超级会员用户。
其次,定义接口时,竟可能让该接口粒度细化只包含该角色层面,比如知名的开发框架dubbo中很多接口是只包含一个方法的,即便让一个类实现多一点的接口。
单一职责,用大白话说,不要把代码写在一起,且按角色分类。
开闭原则
开闭原则是后面一系列规则的鼻祖,这里要重点理解。
一般认为最早提出开闭原则的是伯特兰.迈耶。他在1988年发表的《面向对象软件构造》中给出的。在面向对象编程领域中,开闭原则规定软件中的对象、类、模块和函数对扩展应该是开放的,但对于修改是封闭的。这意味着应该用抽象定义结构,用具体实现扩展细节,以此确保软件系统开发和维护过程的可靠性。开闭原则的核心思想也可以理解为面向抽象编程。典型的案例,就是SPI。
开闭原则,用大白话说,就是允许扩展,不允许修改。
典型的落地方式有,继承,AOP,SPI。继承待扩展的类,编写拓展代码和属性。
这是计算面积的例子,我想扩展π的精度。通过继承类编写覆盖方法。
里式替换原则
是一种从兼容性上出发思考的原则,是实现开闭原则的重要方式之一,她是开闭原则的一种落地实现。
如果S是T的子类型,那么所有T类型的对象都可以在不破坏程序的情况下被S类型的对象替换。简单来说,子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说,当子类继承父类时,除添加新的方法且完成新增功能外,尽量不要重写父类的方法。这句话包括了四点含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
子类可以增加自己特有的方法。
当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松。
当子类的方法实现父类的方法(重写、重载或实现抽象方法)时,方法的后置条件,即方法的输出或返回值要比父类的方法更严格或与父类的方法相等。
用抽象类代替普通父类,在抽象类中实现公共方法,在子类中做具体功能的拓展。
典型的案例,信用卡,和储蓄卡,信用卡消费是生成还款单,而储蓄卡消费则是扣减金额。
迪米特法则原则
迪米特法则是指一个对象类对于其他对象类来说,知道得越少越好。也就是说,两个类之间不要有过多的耦合关系,保持最少关联性。迪米特法则有一句经典语录:只和朋友通信,不和陌生人说话。也就是说,有内在关联的类要内聚,没有直接关系的类要低耦合。这样的例子在我们生活中也随处可见,就像家里的水管装修,有洗衣机地漏、卫生间地漏、厨房地漏,但它们最终都汇到同一个污水处理系统里。在平常使用时,我们不会考虑这些水管是怎么关联流向的,只需要考虑最上层的使用即可。
迪米特法则有一句经典语录:只和朋友通信,不和陌生人说话。
举个例子,校长,老师,学生。
校长想知道每个班有多少学生,应该只和老师沟通,而不是自己计算。计算学生的任务交给老师。
校长和老师沟通,老师和学生沟通。
接口隔离原则
所谓接口隔离原则,即尽量避免,一个类实现了一个接口之后,需要实现一些他不需要的功能。接口隔离是为了高内聚、低耦合。在实际的业务开发中,通常会先定义好需要开发的接口,并由各个服务类实现。但如果没有经过考虑和设计,就很可能造成一个接口中包括众多的接口方法,而这些接口并不一定在每一个类中都需要实现。
这样的接口很难维护,也不易于扩展,每一次修改验证都有潜在的风险。
在具体应用接口隔离原则时,应该根据以下几个规则衡量。
- 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
- 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
- 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素, 环境不同,接口拆分的标准就不同,要深入了解业务逻辑。
- 提高内聚,减少对外交互。让接口用最少的方法完成最多的事情。
典型的案例,在spring框架和dubbo框架中的很多接口,只有一个方法。
依赖倒置原则
依赖倒置原则,是指在设计代码架构时,高层模块不应该依赖于底层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒置原则其是实现开闭原则的重要途径之一,它降低了类之间的耦合,提高了系统的稳定性和可维护性,同时这样的代码一般更易读,且便于传承。他也是实现开闭原则的一条途径。
举个例子,在互联网的营销活动中,经常为了拉新和促活,会做一些抽奖活动。这些抽奖活动的规则会随着业务的不断发展而调整,如随机抽奖、权重抽奖等。其中,权重是指用户在当前系统中的一个综合排名,比如活跃度、贡献度等。
首先是按照抽象接口IDraw 实现各自的抽奖的实现。
然后呢生成以下工具类,供应用层调用。
在这个类中体现了依赖倒置的重要性,可以把任何一种抽奖逻辑传递给这个类。这样实现的好处是可以不断地扩展,但是不需要在外部新增调用接口,降低了一套代码的维护成本,并提高了可扩展性及可维护性。另外,这里的重点是把实现逻辑的接口作为参数传递,在一些框架源码中经常会有这种做法。