面向对象设计模式

设计模式(Design Pattern)

概念:是一套被反复使用(设计套路),多人知晓,经过分类编目的项目实践活动中的经验总结,是某一类典型问题的解决方案
来源:建筑的设计模式(装修房屋,和自已装修对比)

简单的讲:所谓模式,就是得到很好研究的范例,设计模式就是设计范例。
模式不是框架,也不是过程,也不是简单的问题解决方案,它必须是典型问题的解决方案,是可以让学习者反复使用,有研究价值和交流价值。

模式不能套用,不要以为在任何一个系统中都要使用某些设计模式。系统的设计也不是含有设计模式越多就越好。

设计模式的本质是面向对象方法的实际运用。具体而言,是封装,继承和多态的反复使用。可以说,现在市面上关于设计模式的书没有一本适合初学者

要真正理解设计模式就需要透彻理解面向对象设计原则,和面向对象三大特性。

设计原则

定义:指导面向对象编程的规范,通过遵守设计原则可以得到代码更好的质量(可阅读性,可维护性,可扩展新,和可测试性)

1)单一职责原则(SRP)

  • 不要存在多于一个导致类变更的原因。简单的说,即一个类只负责一项职责
  • 不能为图代码量少,把不同职责的类合并成一个类

2)开闭原则(OCP)

  • 对扩展开发,对修改关闭。
  • 主要是为了向下兼容

3)依赖倒置原则(DIP)

  • 高层模块不应该依赖底层模块,二者都应该依赖于抽象;抽象不应该依赖于具体,具体应该依赖于抽象
  • 所谓的抽象就是定义接口
  • 接口和抽象类的区别:接口相当于一种协议(完全的抽象),抽象类:半抽象类(有数据,成员变量)
  • 总结:多用抽象的接口来描述相同的动作,降低实现类与类的耦合度,从而实现低耦合高内聚的最高原则。(一开始不应该写具体的类,应该提取出公共的东西)

4 接口隔离原则(ISP)

  • 客户端(接口的使用者)不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。(只需要使用的接口)

5)迪米特原则(LKP):又叫最少接触原则

  • 一个类对自已所依赖的类知道的越少越好,也就是说,对于被依赖的类来说无论逻辑多么复杂,都尽量的将逻辑封装在类的内部,对外处理提供public方法,不泄露任何信息。

6)里氏替换原则(LSP)

  • 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
  • 子类可以增加自已特点有的方法
  • 当子类的方法重写父类的方法时,方法的前置条件(方法的参数)要比父类方法更宽松
  • 当子类的方法实现父类的抽象方法,方法的后置条件(方法的返回值)要比父类的方法更严格
  • 总结:用尽量不要重写父类的已经实现的方法,可以接口等其他方法实现。

7)低耦合高内聚(最高原则)

UML(Unified Modeling Language)统一建模语言

概念:是目前面向对象软件开发流行的用于分析和设计的标准建模语言
画类图的工具:EA

  1. 用例图:用于分析用户需求
  2. 静态图:用于显示系统的静态结构
  3. 类 图:用于分析和设计类与类之间的关系
  4. 对象图:用于分析和设计对象与对象之间的关系
  5. 序列图:用于描述对象之间的交互顺序
  6. 状态图:用于描述对象的所有状态以及事件发生而引起的状态之间的转移
  7. 协作图:用于描述对象之间的合作状态,侧重对象之间的消息传递
  8. 活动图:用于描述用例要求所要进行的活动以及活动时间的约束关系
  9. 部署图:用于描述系统中硬件的物理结构

类与类的关系

分类为:纵向关系和横向关系

纵向关系

  • 继承关系,它的概念非常明确,也就是面向对象三大特性之一
  • UML表示法:实线+三角箭头(箭头指向的类为父类)
  • 虚线+三角箭头(箭头指向的接口)

横向关系

  1. 依赖关系:一个类依赖与另一个类,而另一个类并不依赖其他类,这种关系是一种偶然的,临时的,非常弱在关系

    UML表示法:虚线+箭头
    举例:人依赖与空气,但空气并不依赖人
    
  2. 关联关系:两个类之间的一种长期的,平等的,可相互调用的关系。分为单向和双向的关系

    UML表示法:实线+箭头
    举例:朋友之间的关系
    
  3. 聚合关系:是关联关系的一种特例,它体现的是整体和部分拥有的关系。整体和部分之间是分离的,各有各的生命周期。

    UML表示法:空心菱形(整体)+实线+箭头(部分)
    举例:班级和学员
    
  4. 组合关系:是关联关系的一种特例,它体现的是整体和部分拥有的关系,整体和部分之间是不可分离的,整体的生命周期的结束意味着部分也结束。

    UML表示法:实心菱形(整体)+实线+箭头(部分)
    举例:人与心脏的关系
    

单列模式(Singleton模式)

1) 定义:是用于创建只有一个实例的类的解决方案

单列模式有两种实现方式:懒汉式和饿汉式
饿汉式:天生支持线程安全
懒汉式:线程安全要加锁(线程同步锁synchronized)

特点:
    1.只能实例化一个对象
    2.单列类必须自已创建自已唯一实例化对象
    3.单列类必须给所有其他对象提供统一的对象获取方法

2) 优点:

3) 缺点:

4) UML类图怎么画:只有一个类(不用画)

5) 使用场景:只需要一个类的实例

单例模式实现过程如下:

  • 首先,将该类的构造函数私有化(目的是禁止其他程序创建该类的对象);
  • 其次,在本类中自定义一个对象(既然禁止其他程序创建该类的对象,就要自己创建一个供程序使用,否则类就没法用,更不是单例);
  • 最后,提供一个可访问类自定义对象的类成员方法(对外提供该对象的访问方式)。

直白的讲就是,你不能用该类在其他地方创建对象,而是通过该类自身提供的方法访问类中的那个自定义对象。

那么问题的关键来了,程序调用类中方法只有两种方式:

  • 创建类的一个对象,用该对象去调用类中方法;
  • 使用类名直接调用类中方法,格式“类名.方法名()”;

上面说了,构造函数私有化后第一种情况就不能用,只能使用第二种方法。
而使用类名直接调用类中方法,类中方法必须是静态的,而静态方法不能访问非静态成员变量,因此类自定义的实例变量也必须是静态的。
这就是单例模式唯一实例必须设置为静态的原因。

工厂设计模式

定义:专门负责将大量有共同接口的类实例化;工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化的类

工厂模式有三种形态:

1)简单工厂模式:又叫静态工厂方法

2)工厂方法模式:又称为多态性工厂模式或虚拟构造子模式

3)抽象工厂模式:又称工具箱模式

一: 简单工厂模式:专门定义一个类来负责创建其他类的实例,被创建的类实例通常具有共同的父类

缺点:

  • 由于工厂类集中了所有产品的创建逻辑,一旦不能正常,整个系统都要受影响
  • 使用简单工厂模式将会增加系统中类的个数,在一定程度上增加了系统复杂度,性能有所下降
  • 系统扩展困难,一旦添加新产品,就不得不修改工厂逻辑,在产品较多的时候,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护

优点:

  • 得到更好的可扩展性,可维护性
  • 工厂类还有必要的逻辑判断,可以决定什么时候创建哪一个产品,客户端可以免除直接创建产品而仅仅使用产品就可以了
  • 客户端无需知道所创建的具体产品类名,只需要知道具体产品对应的参数即可,对于一些复杂的类名通过简单工厂模式可以减少使用者的记忆量

适用场景:

  • 工厂类负责创建的对象比较少;由于创建的对象比较少就不会造成工厂方法中的业务逻辑太过复杂
  • 客户端只知道传入工厂类的参数,对象如何创建对象不关心;客户端既不需要管线创建细节,甚至连类名都不需要知道。

二: 工厂方法模式

定义:一个用于创建对象的接口或者是抽象类,让子类决定实例化哪一个类。工厂方法使用一个类的实例延迟到其子类。

优点:

  • 在工厂方法中,客户端只需要知道产品工厂类即可,不需要知道具体的产品类。
  • 基于工厂类的多态性设计,是工厂方法模式的关键;它能够使工厂可以自主确定创建何种产品对象,而如何创建产品细节则完全封装到具体工厂内部。工厂方法模式之所以又称为多态工厂模式,正是因为所以的具体工厂类都具有同一个抽象工厂类。
  • 使用工厂方法模式在系统中加入新产品时,无需修改抽象工厂类,也无需修改客户端,也无需修改其他的具体工厂类和具体产品,而只需要添加具体工厂类和具体产品类,这样系统的可扩展性也就变得非常好,完全符合“开闭原则”

缺点:

  • 在添加新产品是需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将增加两个类(成对增加),在一定程度上增加了系统的复杂度,会给系统带来额外的开销(降低了性能)

使用场景

  • 工厂类负责创建的对象比较多,由于具有很好的扩展性,对系统的影响较小

三:抽象工厂模式

定义:提供一个创建一系列或相互依赖的对象接口,而无需指定它们的具体类

优点:

  • 隔离了具体类的创建,使得客户端不需要知道具体产品类
  • 当一个产品族中的多个对象被设计一起工作时,它能够保证客户端始终只使用同一个产品族中的对象,也就是我们的工厂没变

缺点:

  • 添加新产品对象时,难以扩展抽象工厂以便生产新种类产品

使用场景

  • 一个系统的产品族有多于一个产品族,而系统只使用其他某一个产品族的产品
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章