第一章:设计模式相关内容介绍
设计模式概述
软件设计模式产生的背景B
“设计模式”最初并不是出现在软件设计中,而是被用于建筑领域的设计中。
软件设计模式概念
是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结,它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。
学习设计模式的必要性
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性,继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点。
可以提高程序员的思维能力,编码能力和设计能力。
使程序更加标准化,代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
使设计的代码可复用性高,可读性强,可靠性高,灵活性好,可维护性强。
UML图
统一建模语言,是用来设计软件的可视化建模语言。他的特点是简单,统一,图形化。能表达软件设计中的动态与静态信息。
UML从不同的角度出发,定义了用例图,类图,对象图,状态图,活动图,时序图,协作图,构件图,部署图等9种图。
UML类图
1.表示方法
类图是显示了模型的静态结构,特别是模型中存在的类,类的内部结构以及它们与其他类的关系等。类图是面向对象建模的主要组成部分。
类使用包含类名,属性和方法接具有分割线的矩形来表示,如下图:
+:表示public,-:表示private,#:表示protected
属性的完整表示方式是:可见性 名称 :类型 [=缺省值]
方法的完整表示方法是:可见性 名称(参数列表)[:返回类型]
2.类与类之间关系的表示方法
2.1关联关系
关联关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生,师傅和徒弟,丈夫和妻子等。关联关系是类与类之间最常用的一种关系,分为一般关联关系,聚合关系和组合关系。我们先介绍一般关联。关联又可以分为单向关联,双向关联,自关联。
2.1.1一般关联关系
2.1.1.1单向关联
用一个带箭头的实线来表示。如上图表示每个客户都有一个地址,这通过让Customer拥有一个地址的成员变量来实现。
2.1.1.2双向关联
所谓的双向关联就是双方各自持有对方类型的成员变量。
在UML类图中双向关联用一个不带箭头的直线表示。
2.1.1.3自关联
用一个带箭头指向自身的线表示。上图的意思就是Node类包含类型为Node的成员变量,也就是“自己包含自己”。
2.1.2聚合关系
聚合关系是关联关系的一种,是整体和部分之间的关系。
聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。例如,学校和老师的关系,学校包含老师,但如果学校停办了,老师依然存在。
在UML类图中,聚合关系可以用带空心菱形的实线来表示,菱形指向整体。
2.1.3组合关系
组合表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系。
在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在了,部分对象也将不存在,部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。
在UML类图中,组合关系用带实心菱形的实线来表示,菱形指向整体。下图所示是头和嘴的关系图:
2.1.4依赖关系
是一种使用关系,它是对象之间耦合度最弱的一种关联关系,是临时性的关联。在代码中,某各类的方法通过局部变量,方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。
在UML类图中,依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类。下图所示是司机和汽车的关系图,司机驾驶汽车:
2.1.5继承关系
继承关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系。
在UML类图中,继承关系用带三角空心箭头的实现来表示,箭头由子类指向父类。
2.1.6实现关系
接口和实现类的关系。在这种关系中,类实现了接口,类中的操作实现了接口中声明的所有的抽象操作。在UML类图中,实现关系使用带空心的三角箭头的虚线来表示,箭头从实现类指向接口。
软件设计原则
在软件的开发中,为了提高软件系统的可维护性和可复用性增加软件的可扩展性和灵活性,程序员要尽量根据6条原则来开发程序,从而提高软件开发的效率,节约软件的开发成本和维护成本。
开闭原则
对扩展开放,对修改关闭。在程序需要扩展的时候,不能去修改原有的代码,实现一个热插拔的效果,简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
例如搜狗输入法的皮肤设计:
分析:用户可以根据自己的喜好更换自己输入法的皮肤,也可以在网上下载新的皮肤,这些皮肤有共同的特点,可以为其定义一个抽象类(AbstractSkin)而每个具体的皮肤是其子类(DefaultSkin,HeimaSkin...),用户可以根据需要选择或者增加新的主题,而不需要更改原先的代码,所以它是满足开闭原则的。
里氏代换原则
任何基类可以出现的地方,子类一定可以出现。子类可以扩展父类而不能改变父类原有的功能,即子类继承父类的时候除新增加的功能外,尽量不重写父类的方法。
例如正方形不是长方形
在数学里,正方形也是长方形的一种,所以正方形可以继承长方形。
依赖倒转原则
高层模块不应该依赖低层模块,两者都因该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块的耦合。
例如组装电脑,需要cpu,硬盘,内存条。只有这些配置都有了,计算机才能正常的运行。选择各种配件有很多选择。
以上案例违反了开闭原则,修改后如下
接口隔离原则
客户端不应该*依赖于它不是用的方法;
比如A类有方法1和方法2,B类需要方法1,如果直接B类继承A类的话,B类就有了A类的方法,但是B类*依赖了A类中的其他方法。
一个类对另一个类的依赖应该建立在最小的接口上。
改进方式:
安全门案例
改进后
迪米特法则
最小知识原则,只和你的直接朋友交谈,不和“陌生人说话”
其含义是:如果两个软件实体无需直接通信,那么就不应该发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相互独立性。迪米特法则中的“朋友”是指:当前对象本身,当前对象的成员对象,当前对象所创建的对象,当前对象的方法参数等,这些对象当前对象存在关联,聚合或组合关系,可以直接访问这些对象的方法。
例如明星和经纪人的关系实例
明星全方位投身艺术,各种事物由经纪人负责处理,如粉丝见面会,和媒体的商务会谈等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人。所以适合迪米特法则。
合成复用原则
尽量使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。通常类的复用指的是继承复用和合成复用两种。继承复用有以下缺点:
1.继承复用破坏了类的封装性,因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
2.子类和父类的耦合度高。父类的实现的任何改变都会影响到子类,不利于类的扩展和维护。
3.限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。
采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,他有以下优点:
1.它维持了类的封装性。因成为对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
2.对象间的耦合度低。可以在类的成员位置声明抽象。
3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。
例如:
改进后: