因为是个人复习java的总结,所以结构稍显杂乱,有些语句过于口语化.
下面主要是对于设计模式的一些介绍,个人感觉分析的不是很透彻,有的理解实在是到了写出来的时候就不好表达,还是需要在写代码中体悟.
建议大家可以到下面的网站中进行学习,至于博客也没什么好看的,我粗略看了一下,很多博客都是直接抄的这个链接,没有一点自己的讲解.不过确实这个设计模式有点抽象不太好写,主要是个人理解.
https://www.runoob.com/design-pattern/design-pattern-tutorial.html
下面我写的有的可能不太准确,有兴趣可以姑且看看,这里只作为我个人的一个记录,因为很多都是从我个人的理解出发的,肯定会有些问题.
其实就是web中的监听器,主要就是在发生某件事的时候获取到,并进行一些操作.
具体的监听器有很多,就不写了,想要用到的时候再查一下文档.这里写一下对于ServletContext
对象的监听器
创建一个类实现ServletContextListener
接口,然后再使用@WebListener
或者在web.xml中配置
就可以实现监听器.其中具体会有两个方法分别在ServletContext
创建和销毁的时候执行,那么就可以考虑在监听器监听到ServletContext
创建的时候加载一些服务器开始运行就需要的文件,然后再销毁的时候也可以做一些保存或者其他的一些操作.
这个模式在我的理解中就相当于将具体的数据的实体类归结到一个抽象接口中,然后再写一个这个抽象接口的工厂类,专门用于获取这个接口下的实体类对象.这样做可以很好地增加代码的复用性,避免不同实体类其实操作差不多却要反复写代码.
看完这个模式真的对之前写的网站中的一个困扰豁然开朗,之前网站中对于数据库的访问就因为只是不同的数据实体类,集成操作到一起的时候就很不好明确类型,具体在什么表进行操作,然后又不想在操作或者服务中写if判断,那样后面更不好维护.最后是采用了类似工厂模式的方式解决,数据先传,在必须要判断的时候使用一个封装了通过反射获取实体类的类进行操作.后面也发现不太好维护,每次增加都要增加对应的数据库操作.
如果采用工厂模式会更好一些,只要去维护这个工厂类和实体类,对于整体的代码逻辑影响不大.
看到教程中还有应用到日志和连接服务器的框架,也可以大概想象到,主要就是对于一些可以忽略具体数据类型进行操作的情况使用,不管是数据的输入还是输出.
这个模式在我看来就像是上面工厂模式的增量,上面是使用工厂类封装抽象,而抽象工厂直接是用抽象工厂来封装工厂类.也就是说之前是考虑需要不同数据,而现在考虑的是生产不同数据的工厂.这不就是java中很多底层的类都是这样一层套一层的,就是面对对象的思想,我只考虑我需要什么的时候可以找到什么对象拿到.
教程中的使用场景也很好理解,qq换肤相当于是把一系列的衣服表现为一个工厂,我需要就去这个工厂给他全拿出来,这样就能整套换,而不用因为他在界面上是分开的不同部分而一件一件去找.然后生成不同操作系统的程序也类似,不会把不同系统的程序混在一起.
但是其实也很明显看得出来,这样做想要扩展那就很麻烦,从最底层到上层都要进行修改,如果只是想在深度上扩展那有很方便.
看完也是很有体悟,之前写网站的时候也是类似这样的情况,结果选择了加到整体的结构中,花了很大功夫修改,现在这样想想,确实可以考虑在深度上扩展,那样虽然类多了一些,但是逻辑更加明晰.
其实就是一个类只有一个实例化的对象,主要就是为了空值资源,避免一些类的过度实例化,或者说这个类本来就不能或不适合有多个.这个概念其实之前学计算机操作系统的时候有了解过,这里复习一下.
懒汉式,相当于比较懒等你访问了,我才会去看是不是已经实例化了这个对象,当然这个获取被加了锁,不加锁的话肯定会出现重复创建对象的问题的.这样做比较省资源,但是性能有点低,毕竟如果不是操作非常频繁,出现冲突的情况很少,但是却加了锁.
饿汉式:相当于我先创好了对象,就等你来获取,这样就不需要加锁,效率相对来说比较高,但是很可能造成资源浪费,这对象放着也没人用.
双重校验锁,相当于是在懒汉式的基础上只对创建对象这个过程进行加锁,如果有对象了就像饿汉式直接拿,如果没有对象那就等锁创建.这样效率和安全都比较好.
静态内部类的方式,很有意思
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
相当于是加锁的问题交给了虚拟机解决,这样做确实比较精确的控制只有需要这个资源的时候才创建,但是也只适用于静态域
枚举的方式,则更加简洁,而且因为枚举的特性,也很安全.
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
这个模式相当于是说对于一些复杂的对象,也就是其中的对象可能是各种关联对象的时候,将创建这个整体对象的操作独立出来作为一个类.那么在实际使用的时候就不需要去为了创建这个复杂对象而创建一系列对象,这些过程都被封装到了一个builder中.只需要创建builder类的对象就可以获取整体复杂对象的内容.
这个模式在之前也遇到这个问题,但是没有考虑到将这个过程独立出来.网页的整体作为一个对象,因为需要从后台查询数据,如果分的数据模块比较多,那就可以考虑使用这个方式进行实现,
这个模式相当于对于一些创建代价比较高的对象,通过记录,然后实现能够二次创建的时候直接去复制,而不用重复创建过程的效果.
通过类实现Cloneable接口,重写clone()方法达到克隆对象的效果.
相当于是说当你想要使用某个接口的时候,发现这个接口离你的预期差了一点,而差的部分刚好有另外一个接口可以补充.这时候就可以创建一个适配器组装到这个接口下的实现类,那么你在使用这个接口的时候就可以通过这个适配器使用想要的接口中的内容.
或者说就是在A接口里面添加了一个实现类作为适配器,然后A接口的实现类通过这个适配器去使用适配器中使用的另外一个接口.
但是感觉这个模式不太好用,这样改让接口很乱.
相当于是说对于某个接口以及其下的实现类,突然发现,你可以从另外一个角度去理解这个接口,这个接口分的可能不太合理,不是单一的理解,那我们再弄个符合理解的接口去使用原本接口,然后达到我们理解的角度的理解.
有点绕,比如说我们有个画图的接口,下面有画红色圆,画绿色圆,仔细一思考,这不对啊,这可以理解成是画圆形啊,也可以理解成画不同的颜色啊.那我创建一个图形的接口下面实现画圆,然后接口中调用画图接口,那就符合我们理解的角度了.我要画图,什么图,画圆,画什么圆,红色的圆.而不是说我想要画图形,画什么样的,红色的圆.或者把颜色分出来,也是一种理解.
这样做可以把抽象类和实现分开,减少他们之间的密切联系,也就是多出一部分来灵活地沟通抽象和实现.
其实就是一个过滤的概念,对于数据可以用一个抽象的过滤器实现很多不同的过滤实现类,然后调用这个些过滤器,过滤到自己期望的数据.对象也一样.这就像Servlet中的Filter.
相当于是一个类中包含存储自己的List,就像文件夹结构一样,一层存一层
其实这个模式和前面的思想有点像,感觉都是通过新建一个抽象类然后创建原本的抽象类对象,然后达到某些目的.这个模式中是通过新的抽象类继承原本的类,然后在其实现类中添加一些新的功能从而达到对原本的类的功能扩展的效果.
这个模式相当于是在原本的一些类的外面封装了一层创建对象和调用方法的类.用户只需要通过获取这个类的对象,调用方法,而不用考虑具体里面的对象是怎么创建的.也就是相当于把一些类当成了外面这个类的属性,把具体对象的方法显示给用户,用户调用就好了.
这个的应用可能就在比较大型的开发中,有点像框架的感觉.
这个模式相当于是池的概念,主要就是为了减少过多对象的创建带来的资源浪费的问题.在类的外面封装一个工厂类,用户通过工厂类获取其中的对象,然后在工厂类中会进行一些判断,对于已有的资源直接使用,没有的资源再去创建,避免过多的资源占用.
其实这个和String也很像,就是减少不必要的过度创建资源.
这个代理模式相当于是说也像前面一样,在类外面加了一层代理,用户通过这个代理来访问类创建对象,而不能直接访问这个类.而这个代理是通过和资源实现同一个抽象类,然后调用代理来获取资源的实现.
其实可以看出来上面很多模式都是将资源多封装一层来保护资源,减少资源的滥用,只是实现的方式不大相同.
代理模式在java中有一个proxy.newProxyInstance()专门来帮助实现代理,可以不用自己写.这个方法会返回一个和真实类继承相同接口的对象,然后每次调用对象都会调用上面方法中传入的参数中匿名内部类new InvocationHandler()的一个invoke方法
这个代理中其实就是在对下面的业务逻辑不发生改变的情况下,对于传入的参数或者输出进行一些额外的操作或者说是增强.这种代理的模式在之后的框架中会经常涉及到.
这个模式其实可以在Filter中使用,通过代理request对象,对其中的数据进行一些增强,然后再将代理对象代替原本的request传入.这样做之后request中的数据其实没有变化,只有在接收request的servlet中对request进行某些操作的时候,就会调用这个代理类中的数据invoke,然后对数据进行一些增强,或者对返回进行一些增强.
这个模式的概念其实有点像是异常抛出的概念,像是如果当前不能解决就向后推移,直到有人能够解决这个问题.只是这里表达的不是异常,而是对于请求的处理.这个模式主要应用在web上.
就比如说Filter,就是这种模式,用户不需要考虑请求数据的具体处理等问题,Filter会形成一个处理的责任链,在这个链条中通过不同的处理,达到不同数据送达至合理的服务进行处理.
这样做确实可以减少请求和服务器的处理之间的耦合性,这个问题在之前写网站的时候也遇到过,原本已经写好了前端传输的数据,也写好了服务器中的操作,但是后来发现中间有点问题,需要添加一下数据,但是这些数据在服务器里又会对操作造成影响,导致整个操作都要重新写.那时候还没有学习Filter,其实加一层,在Filter中增加一些数据的判断就能解决这个问题.
仔细想想,这种模式其实很常见,这个就很符合逻辑的一种模式,但是问题也确实很明显,这个链条长了,就很难判断问题到底出在哪一步,发送的请求会在那个地方被处理掉.
这个命令模式有点像是数据库中的事务的概念,也就是说对于一些操作和请求之间,他们的联系太紧密了,一请求就处理了这个操作,那如果突然发现之前的操作不太对,那就没法修改.如果把这些操作都封装进一个命令类中,采用类似延时执行命令的方式,那么如果针对不断变换的数据就可以很好地修改命令,想要撤除或改变之前的命令也很方便,只要在命令中添加对应的操作就好了.如果是直接操作命令,那就很难挽回已经执行的命令.
这个模式感觉不太好应用,其中的内容是通过一个解释器来帮助语言或者说是语法的判断,有点像逻辑运算符的重写,对于这个语句中到底是什么意思,通过我这个解释器来调用获取对应的解释.
这个模式其实很熟悉,就是迭代器,再不需要知道集合内部细节的情况下遍历集合中的元素.
这个模式感觉像是类设计上一种建议,就像是一个对象需要进行一些操作,这些操作可能涉及到了多个对象,那么这时候不需要你自己去操作,而是使用一个中介类,这个类中会把你需要的一系列问题都封装了,你调用就可以解决一系列问题.
这也是之前写web的时候遇到的情况,作为控制器的Servlet对应了对于前端请求的内容,其实这个控制器扩展开来写会比较好,一个界面的请求就不会影响到其他页面的请求,但是其中操作的实质,也就是下面的service可以是统一的.我写的时候就将Servlet写在了一起,结果就造成了不好改的麻烦.
中介者表达的应该就是类似说降低对象之间的冲突.
这个备忘录模式比之前的命令模式更接近与实务管理,上面是对于操作命令的一些封装,而这里是对于数据的保存,这样可以做到对于数据的回滚,但是明显保存的数据占用的资源如果比较多,这个备份也会占用比较多的资源,而且还可能不会使用到.
其实就是对于某个类的对象添加了观察类,如果这个对象发生了改变,就需要根据其中写的方法去通知那些观察类,然后其他对象会根据这个变化进行一些改变.但是这个没有遇到过相应的问题,不是很好理解.
这个模式有点像前面命令模式的进化版,前面命令模式是将不同的命令传入,然后不同的命令调用不同的方法.所以命令模式一般只有一个方法,因为命令被细分了.那么状态模式相当于根据对象的状态去调用不同状态下的方法.但是又不用细分这些命令,因为每个状态下的命令都是写好的,也就是说一个状态下可以调用一批的命令,另一个状态下又可以调用另一批的命令.
所以实现的时候应该是在需要添加状态的类中添加状态类,然后去实现不同状态的类,并在其中写好方法,那么调用的时候就可以获取类中的状态,然后根据不同状态的对象去调用方法.
这个方法确实可以简化不想写判断的问题,后面维护也方便一点,对之前写网站中的问题很有启发.
这个空对象模式也很有意思,就是通过主动创建一个与原本创建的类相对应的空对象类,在对于一些操作可能造成创建对象为空的情况下返回这个空对象代替null.
这样做可以减少空指针异常,有利于程序的完整运行.其实这个问题在之前写网站的时候也遇到了,我的操作是通过trycatch返回跟原本类一样的空对象,感觉差不多,但是这种方式可能更加节省资源,效率更高,毕竟其中对于原本类的实现都没有做.
之前状态模式是通过改变状态来选择不同的操作,不涉及对于操作的具体选择,而策略模式有点类似,但是策略模式针对的是不同的实现算法,也就是说对于某个类中的操作的实现,选择一个写好的策略类去执行,那么就会执行这个策略下的方法.主要也是为了不写if判断.实现的层面更为深一点,选择策略的方式也不一样一点.
其实就是写抽象类的一个概念,将通用的部分写好,不通用的实现类根据自己的需求去写.抽象类中的一些整体操作思路很可能不同的实现类是相同的,他们不同的其实只是其中实现的细节,那么就可以final一个整体的逻辑模板,将其中的一些细节方法交给实现类重写.
这个模式相当于是说在一个对象中存在很多其他对象的不关联操作的时候,可以定义一个访问者类,也就是在其中定义了各个部分对象的操作的类,然后在原本对象的操作中调用这个访问者去操作,而不是在原本的类中直接去操作,这样原本类中的对象就不会发生改变,不会对这个对象造成影响.
就是采用存储的数据对象和数据的展示分离,中间通过一个控制器来实时更新两部分之间的关联关系的变成框架.
这个模式和三层## 标题架构有点像,但是有点抽象,整不明白,看来还是得使用到之后才能更好地去理解.
这个模式的感觉相当于是将实体类组合,然后使用外部的实体类对象的时候,可以根据参数去改变内部的实体类对象,从而达到操作组合的实体类的效果.
这个就是之前我写网站的时候用的,相当于是访问数据访问对象的时候,是通过这个数据访问对象的接口去访问,这样做主要是为了更加灵活,底层的一些操作不会直接和上层一些的服务直接相连,那么在修改底层操作的时候就不需要同时修改上层的代码,上层只知道下层有这个接口连接服务.有种面向接口编程的意思.
这个模式相当于是在所有的请求和资源之间设置了一个中间的必经环节,通过这个中间的控制器能够对所有的请求进行记录操作,感觉就像是专门拦截所有请求的并控制去向并记录的Filter.
就是相当于Filter的使用,对于请求进行一些过滤操作,说实话这个在web中真的好用.
其实就是为了减少通过配置定位资源路径的查找方式的损耗,每次为了某个服务都要去查找一次这个资源损耗太大,只有第一次查找需要去找,后面是通过第一次的缓存,从缓存中查找,获取到资源.这样查找资源的损耗会降低,特别是对于频繁使用的资源.
这个有点像前面对于对象的缓存,只是这里是为了减少通过配置查找资源的损耗.
这个模式的概念相当于是将一些数据作为对象传输,也是为了将服务的数据和前端的数据形成对应,方便操作.
这就像之前写网页的时候将分页查询的一些信息封装成为一个对象进行传输.
如有错误欢迎读者批评指正!!