Java 设计模式学习
看完headfirst设计模式,简单总结一下。
写在最前面:设计模式的关心的问题为“弹性、易于维护、易于扩展”,通过对模式的应用,让自己的代码能够得到良好的可塑性。但是个人认为不能调入为了应用模式而使用模式的陷阱当中,使用模式根本的目的依然还是解决问题,如果程序或系统本身就结构清晰等,完全不必要为了追求某一种模式而可以进行代码更改。
1.策略模式。
将容易变化的部分从整体中分离出来,对此部分进行抽象,按照对接口编程的原则进行整理,再通过组合整合至整体中。
优点:避免了一次继承带来的上层修改一点,后面全部都会变化很多的情况
2.观察者模式
通过订阅的方式让对象与被订阅的对象在一定条件下自动交流。
3.装饰者模式
不改变现有对象的基础上,通过对对象的再一次包装,使之具有更多的功能。最典型的例子莫过于java中的IO系统,通过对stream,file等的包装,让其能够适应不同的场景
4.工厂模式
工厂模式用来封装对象创建操作,使得客户不需要去自己new 具体的对象,直接交给工厂即可,同时对于开发者而言,如果要增加新的产品,只需要修改这个工厂即可。
5.单件模式
适用于:对象在全局中唯一,或是创建独一无二的对象。
可使用全局变量达到此效果,但使用全局变量的缺点为需要事先在程序员中约定好。使用单件模式就会克服全局变量的缺点。
其做法为:
- 将独一无二的对象设置为某一类中的private static量,private可以保证除了这个类以外,其他类均不能访问,static可以保证这个量只会被初始化一次。
- 将此类的构造函数声明为private,这样保证了只有此类内部可以进行对象的创建,外部无法进行此类对象的创建。
- 再此类中设置一个public static方法,在这个方法中监测这个对象是否被创建,并返回这个对象,public static 方法提供外界对此类的唯一访问入口,这样就可以得到一个独一无二的对象。
实例如下:
public class A { private static A unique; private A(){ } public static A getInstance(){ if (unique==null){ unique=new A(); } return unique; } }
这样,通过此模式,确保了一个类中只有一个实例,并为外界提供了一个全局访问点。
6.命令模式 Command pattern
如果一种情景为一个事物A请求(命令)另一个事物B,最直接的方法就是A调用B中的方法即可。但这种方法将A和B紧紧绑在一起,A需要了解B中的具体方法是什么,并且如果A若想要在请求事物C,就得在A中添加新代码,不易扩展。
命令模式所要解决的就是让调用者(如A)与行为执行者(如B,C)解耦,A不需要知道我究竟调了哪个方法,只知道当我创建好我想要的命令后,要得到命令的执行。
要达到上述目的,命令模式将命令(请求)封装为接口,具体命令都来实现这个接口。客户端设置给自己设置号具体命令,然后调用接口方法执行即可。在具体命令当中,拥有相对应的执行者实例,通过复写命令的接口方法的来调用执行者中国相应的方法。而在执行者当中,只需要关心自己所能提供的功能与服务即可,不需要考虑谁来调用。(这样便可做到命令的调用和执行解耦)
参与角色:
1.抽象命令接口:所有具体命令皆实现此接口。
2.具体命令:客户端所需要的具体请求或命令。
3.客户 client:用于创建具体命令(请求),并执行这个命令中的接口方法。
4.执行者:命令的执行者。
打个比方来说:我到一家餐馆吃饭,我即为客户,我点一盘鱼香肉丝,我所点的这个含有鱼香肉丝的订单即为具体命令,而订单则为抽象命令接口,我不需要知道谁去做,我只需要创建好这个订单并将订单提供给餐厅即可,餐厅将这个订单送给厨师,厨师即为命令的执行者,厨师看到了这份订单,自然就开始进行选择材料制作鱼香肉丝等一系列行为,厨师也不需要知道谁点了这个,只需要知道这个订单需要鱼香肉丝。
在这个过程中,也许会有个疑问,餐厅所扮演的角色并没有在上述四种角色之中。我在学习命令模式中,大多数命令模式在客户创建完具体命令后都有个调用者(invoker),一般都在客户创建命令之后起到一个传递命令的作用,而整个命令流程可以不需要它即可完成,只是实现方面需要其参与,因此未将其列入上述参与角色当中。
下图为简单示意图
7.适配器模式与外观模式
适配器模式:适配器顾名思义就是将不同的接口进行连接,因此适配器模式要解决的最大的问题即将一个接口包装为我们需要的类型。其中涉及的角色有:
- 客户:通俗意义上的使用者,调用者等
- 目标接口:客户课调用的接口类型或者说是客户想要的接口类型
- 被适配接口:现有的不符合客户要求的接口类型
- 适配器:含有被适配接口并实现目标接口的具体类
客户通过适配器将被适配接口转换为目标接口,然后再进行使用。用示意图表示如下:
外观模式:一句话说即为将一系列具有流程性质或相关性质的方法放入一个统一的方法中,使其在调用时不用再将每一个细节方法都调用一遍。这个打眼一看非常像封装,但和封装最大的区别是外观模式并不阻断用户去调用统一方法中的细节方法,用户依然可以再需要使用细节方法时使用,而封装的话则是将用户与细节方法阻断开,只给用户提供封装后的接口,用户无法调用其中的细节方法。
外观模式虽然简单,但是其中也不是随便讲一堆方法放进去即可,为了以后的维护或者替换考虑。这里需要有一个简单的指导性原则进行一点点约束:最少知识原则。这个原则内容为:尽可能少的让对象之间的交互。这样做有一个明显的好处,当一个类需要改变时,不会太多的影响其他地方的调用。其具体指在该对象方法内,我们只应该调用属于下列范围的方法:
- 对象本身的方法
- 作为参数传进来的对象的方法
- 对象实例化的方法
- 对象的组件
通过这四个简单原则,可以将对象之间的相互方法调用降到最低(并不绝对需要采用此原则,因为解耦的代价为增加代码量)。