第三周总结
本周上课的主要内容是精讲一些常用的设计模式,以及每种设计模式能解决的问题,通过实际的案例分析
,学习常用的软件中的设计模式的应用。
一、基本概念
1.设计模式的定义
设计模式是应用设计原则解决一种问题的通用解决方案,这个解决方案是可以重复使用的。需要注意的是所有的面向对象的,可以复用的解决方案,都是设计模式,并不是特指23种设计模式。
2.设计模式的作用
为了达到OOD的目标(强内聚,低耦合),需要遵守OOD的基本原则,实际上设计原则只是一组概念或者规范,是指导思想,而设计模式就是应用设计原则解决实际问题的最佳实践,是一组可以重复使用的通用解决方案。在实际开发中直接使用这些设计原则,一方面可以提高代码质量,另一方面设计模式是共识,实际上是可以提高代码的可读性。
3.设计模式的分类
从功能上分为:创建模式、结构模式、行为模式
二、常用的设计模式解析
1.简单工厂模式(以及变形)
场景:创建对象的逻辑比较复杂,不需要对外暴露,可以封装对象的创建过程,将对象的创建和使用相分离。
类图:
简单工厂是最常用的设计模式之一,我们可以使用它在不同条件下创建不同实例,简单工厂的变形通过反射来创建具体的实例,通过配置文件维护对象对应的类名。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
2.单例模式
单例模式用来创建全局唯一的对象。一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。
场景:减少实例频繁创建和销毁带来的资源消耗,便于统一管理
类图:NA
单例的用处非常多,默认情况下,spring创建的bean就是单例的(通过一个单例注册表实现的),单例的实现方式也非常的多的,经典的实现方式分别是:饿汉式、懒汉式、双重检测、静态内部类、枚举。
饿汉模式简单好理解,类被jvm加载后就创建了单例的对象,缺点就是有可能这个单例对象一直没有被使用,但是已经在堆内存中了,造成了资源的浪费。
懒汉模式的好处就只有用到单例对象的时候才会去创建对象,当然在多线程的场景下,就会带来线程安全的问题。在方法上加互斥锁可以解决线程安全的问题,但是锁的粒度太粗,锁的范围应该是创建对象的那部分,如果已经存在创建好单例的对象,这个时候去获取对象,是不应该有锁的。
双重检查锁,细化了互斥锁的粒度,只有在创建对象的代码块上了锁,解决了上面提到的两个问题(延迟创建对象,获取对象无锁),但是代码复杂度较高。
静态内部类是使用了jvm类加载机制去创建单例对象,满足上面提到的两个问题,只有在调用Singleton.getInstance()方法jvm才会去加载SingletonHandler类,同时jvm会保证线程安全,不会创建出多个单例对象,一旦初始化完成完成,以后再获取单例对象就是无锁的了,是比较好的解决方案。
枚举也属于饿汉模式的一种方式,通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。
3.适配器模式
场景:适配器模式是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。
类图:
适配器模式更多的是系统设计不合理,兼容有问题的补救措施。
4.模板方法模式
场景:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
类图:
HttpServlet中的service方法是模板方法,定义了doGet、doPost、doHead、doPut、doDelete等方法的执行流程,我们自己的Servlet只需要重写相关的方法就可以实现在使用不同的http method的情况下,调用不同的方法。
5.策略模式
场景:一个类的行为或其算法可以在运行时更改,其实就是面向接口编程,用来避免 if...else 所带来的复杂和难以维护。
类图:
6.组合模式
场景:主要是用来处理树形结构数据,用来代替递归算法,是程序职责单一、扩展性可读性更好。
类图:
组合模式,将一组对象组织成树形结构,将单个对象和组合对象都看作树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。
具体参考作业
7.装饰器模式
场景:在不改变对客户端解耦的前提下,扩展现有对象的功能
参考代码:
装饰者模式的特点是,装饰的类会由构造方法传入被装饰的对象,由于装饰者和被装饰者都是继承同一个接口,所以装饰和被装饰是可以调换的。
例如要把项目中session替换成分布式的session,而不改变已有的程序。
三、案例分析
1.Junit
依赖倒置原则 + 策略模式 + 模板方法模式
首先Junit的设计就是遵循的依赖倒置原则,只要遵循Junit的抽象写测试用例,Junit框架会来调用测试用例的程序
策略模式,可以看成有两种策略模式
Eclipse -> Eclipse plugin 规范(策略)->Junit (实现)
Eclipse -> Test Case (策略) -> XyzTest (实现)
模板方法模式,TestCase类中runBare方法就是模板方法,它定义了setup、runTest、tearDown方法的执行流程,我们只需要去继承TestCase,并且按需重写setup、tearDown 方法即可。
Junit是比较典型的使用策略模式+模板方法模式的案例。
2.Java Servlet
两个模板方法模式
一个是HttpServlet中service方法,定义了doGet、doPost、doHead、doPut、doDelete等方法的执行流程;
另一个是web容器执行servlet的 init service destory方法的执行流程。
3.Spring中的设计模式
依赖注入DI于控制反转IOC
单例模式
SpringMVC模式
4.Panthera
单一职责原则(generator、transformer 抽象)
装饰者模式
四、总结
学习设计模式最大的问题是“一看就会,一写就忘”,如何能在实际开发中活学活用,就需要我们能掌握每种设计模式能解决的问题,在遇到这个场景马上就能想到要用这个设计模式。除此之外,要对坏味道的代码要有敏锐性,及时发现代码的问题,这样才能对症下药。最后设计模式是架构能落地的最好的手段。
评论