前
记录一下我对各种设计模式的理解,不会详细介绍设计模式内容
正
外观模式
外观模式的意义在于, 当存在一个复杂的子系统,子系统中有多个模块,对于外界
来说,这些模块的意义或许很难理解,导致很难正确使用,当然只是对于不同模块难以区分时,可以使用外观模式,对外一个简单功能的类或接口,外部调用子系统功能都通过这个接口,而接口内部封装好各个模块的功能,根据入参来选择不同的模块功能。
中介者模式
中介者模式和外观模式很难区分,因为实现基本上没有大的差别,都是使用一个接口来封装很多模块的功能,区别在我看来,在于是否对外,中介者模式是为了系统内部的不同模块之间的通信,而外观模式是对外,这一点从名称上也可见一斑。
享元模式
这是一个比较有趣的设计模式,最好理解的例子就是游戏,游戏中经常有大规模的重复对象,例如fps中的子弹,可能会分不同规格的子弹,但是统一规格的子弹,那数量也非常大。但是我们在内存中不能去创建这么多对象,否则一场战争下来,内存会炸。这里就是使用享元模式,也就是池化一个对象,或者称为对象池,但值得注意的是,被池化的对象本身包含的是可共享的,一般分为内在状态和外在状态,内在状态包含不变的,可在多个对象中重复使用的变量,外部状态是各个情景中不同的变量,一般由参数传递进来。
实现来说,享元模式就是一个工厂类,内部维持一个容器,当外界需要对应的对象时,从其中获取,如果没有对应的,就新建一个,有则直接取出使用。但是不能去修改。
适配器模式
这个模式比较好理解的例子就是充电器转接头,现在手机的充电器有很多种,所以很多时候就没办法使用别人的,这就需要充电器转接头。而适配器模式也就是这个功能,还是比较简单的,从实现来说,一般就是有两个不同的接口,那么适配器类实现其中一个,然后内部引用另一个接口的实现类,在对应的接口方法中,转换对应的参数和返回值。
装饰器模式
这个模式比较好理解,就是为了设计模式原则中的开闭原则,面向新增开放,面向修改关闭,当有同一个接口的一个或者多个实现类需要额外的操作时,我们可以使用模版模式抽象出一个抽象类来汇聚这些额外的操作,也可以使用装饰器模式,创建一个装饰者类,接收一个实现类,在对应的接口做额外的操作前或后,再调用原来的方法。
这个模式我印象比较深的Dubbo里面transport层的实现,对于接口channelHandler的实现,真正处理消息的只有一个实现类,其他基本上全部时装饰者类,例如多线程的封装类,解码处理器(处理Decodeable),多消息处理器,心跳处理器等等。
模版方法模式
这个模式我用的还是比较多的,在业务中非常常用,也非常好用。他是为了解决同一个接口的多个实现类中有大量重复逻辑的问题
从实现来看,对于一个接口的多个实现类,根据重复的代码,抽象出一个抽象类,然后将实现类中不同的部分以抽象方法暴露出来,供字类实现。
其中有一个点时,如何决定使用哪一个实现类(当然除了明确知道的情况),一般需要在外部再封装一个实现类,根据匹配情况,调用不同的接口,这一般需要接口额外出一个match接口,各个实现类实现自己的匹配逻辑,这就要求这些匹配逻辑不能有重复的部分,不然就需要注意遍历实现类的顺序。
当然实现的方案有很多,比较巧妙的方式是通过动态代理的方式,实现自动注入。
(抽象)工厂方法
简单来说既是把对象的创建和使用分开,将创建使用一个工厂类封装,内部可以封装一些选择逻辑,这样新增一种类型时,不需要修改调用侧,只修改工厂方法即可。
抽象工厂是在工厂方法的基础上,如果需求有多维度的接口聚合生成一个对象,例如,我们是一个家具店,首先要创建一些家具类,有椅子,有衣柜等等,在这个基础上呢,家具又有很多风格,国风也好,意大利,欧美风什么的,那么我们就可以先创建一个家具工厂类,然后在这个类基础上,我们可以创建国风家具工厂类,欧美风家具工厂类等等。
然后在应用层,根据调用创建对应的工厂类。
原型模式
这个模式比较简单,就是克隆类,值得注意的是,要进行深拷贝。
这里说一下java的Cloneable接口,这是个空接口,但是如果字类要重写Object#clone方法的话,必须要实现这个接口。
然后说一下clone方法,这个方法在object,是native方法,访问权限是protected,字类无法访问到,必须重写。
一般重写会调用super.clone(),这个就是调用object的native方法,会复制一份,但是对于该对象内部的属性却是浅拷贝,如果含有引用类型的属性,只拷贝了引用,对象还是一个,所以一般需要对应引用类型的类也实现Cloneable接口,实现clone方法。
不过这种方式个人觉得不好,使用静态工厂方法或者工厂类,自己实现拷贝逻辑比较好,当然对于数组而言,可以使用clone。