- 在讲模版方法模式之前我们先了解下java设计模式,一共有23种设计模式,可以分为3大类:
- 创建型模式
- 结构性模式
- 行为型模式
- 再讲写设计模式的6大原则
- 开闭原则:对扩展开放,对修改关闭,为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,需要使用接口和抽象类。就是说写出来的代码,如果在业务发展变化下,能扩展,不需要去修改原有的代码,这样的代码就符合开闭原则。
- 里氏代换原则(LSP):任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
- 依赖倒转原则:这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
- 接口隔离原则:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思。
- 迪米特法则(最少知道原则):为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。从被依赖者的角度来说:只暴露应该暴露的方法或者属性,即在编写相关的类的时候确定方法/属性的权限。从依赖者的角度来说,只依赖应该依赖的对象。
- 合成复用原则:原则是尽量使用合成/聚合的方式,而不是使用继承。
- 模版方法模式(templete)
模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:
抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。
抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。
实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。
模板类:
其中meA()模版方法,规定了主要的逻辑流程。
meB()和meC()就是抽象方法,具体的实现在子类中。
isRight()方法就是钩子方法,一般返回boolean类型,子类中可以是覆盖,返回不同的值,来改变模版方法中的逻辑。
其中一个子类:
测试类:
java中的InputStream,OutputStream,Reader,Writer类中的非抽象方法都是模板方法。
spring中最常用的完成DAO层操作的JdbcTemplate就使用了模版方法模式。
执行sql语句的步骤简化如下:
打开Connection
设置事务
执行sql
提交事务
关闭Connection
这个顺序没法省,也没法打乱。如果我们每执行一次SQL,都要按这种顺序写代码,代码重复的太多了。模板方法模式可以帮我们解决。
模版类:
模版方法:
看execute()这个方法的代码应该就能很好理解了。多说一下钩子方法,也就是useTx()。
我们执行SQL语句,有的是需要启用事务的(增删改),有的则不需要(查),但是抽象类是不知道哪个SQL用哪个不用的,这个选择权就只能交给具体的实现类来决定。
useTX()方法并不是执行SQL所必须的步骤,但是它却可以将相关步骤进行挂钩。
你想用事务,将useTX()返回true,execute()就会执行事务相关的方法——通过useTX()这个钩子,把事务方法挂了上去。
你不想用事务,将useTX()返回false,execute()就不执行事物相关的方法——通过useTX()这个钩子,把事务方法从原方法上脱了钩。
具体的子类就可以自己去实现抽象方法就可以了,具体的执行流程都在模版类中控制。也可以通过覆盖钩子方法,来控制某些特别逻辑。