一、设计模式概念
设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性
二、几种常用的设计模式
1、单例模式
保证每个类只有一个实例。
例如 一个学校类只能有一个校长,资源管理器只能打开一个等。。
创建单例:构造函数是私有的,然后写一个static方法,返回对象。分为恶汉和懒汉式。
懒汉存在线程安全问题,例如a线程进去了,刚判断完 object==null,不等于null,进去了。然后控制权到b线程,b进去创建了一个实例,到a,a也创建一个实例。所以需要加同步锁。
(ps:caldener不是单例的,
并没有指向同一个内存地址。)
2、工厂模式
一般用于创建对象。创建对象的时候不会对客户端暴露接口(new Circle()是在工厂类中干),只会用统一的接口来创建对象。
例如一个Animal接口 say方法,如果一个dog和一个cat实现类去实现Animal接口。
可以用 Animal a = new Dog(); Animal a = new Cat();
但不同的情况下会运行不同的实现类。这样可以根据 实例化工厂类。调用工厂类方法,根据传入的参数判断是需要new哪个实现类。
这个和spring依赖注入很像,注入一个接口。通过name属性来决定需要哪个实现类。
抽象工厂类就是两个接口,每个接口都有两个实现方法。这样的话你要是写两个工厂类就不好了,就把两个工厂类向上抽取成一个接口。然后就用工厂类 对象名 = 工厂类的工厂类(参数)返回需要用哪个工厂类,在工厂类去弄。(一个工厂里有多个产品)
总结:
一个接口,两个实现类,一个工厂类(决定用哪个实现类)
两个接口,四个实现类,两个工厂类,工厂类的接口,工厂类的工厂类(决定用哪个工厂类)
3、代理模式
一个类代理另一个类的模式,例如 明星和经纪人,你可以通过经纪人代理与明星进行通话。一般像一个类不想被访问啊,
或者说对象在别的服务器等。。。
静态代理:
被代理类:RealTest 代理ProxyTest
这两个类同时实现一个接口 Test,这样调用的时候,Test test = new ProxyTest();
test.show(); 代理类中的show方法再调用RealTest()方法的show().
这是静态代理,动态代理没搞懂,只是了解 被代理的字节码文件是在运行的时候通过反编译出来的。(老子现在搞懂了,嘻嘻~)
场景:
0、例如玩游戏,你要是玩韩服lol,就需要代理服务器,因为服务器在人家那里,你不代理就很卡
1、某个类不想被访问
2、不同的权限的人对被代理类的访问权限不一样。这样就可以在代理类中处理
(小例子啊:例如访问代理类同一个方法,小红访问可能去被代理类的a方法,小明就去了b方法)
动态代理:被代理的字节码文件是在运行的时候通过反编译出来的
试想一个被代理类,就得需要一个代理类,那被代理类多了呢,所以很麻烦。
并且,如果接口改了,代理类和被代理类都需要修改源代码,low b~ 所以就有了动态代理。
实现思路:写一个动态代理类,实例化接口中被代理的类,然后通过jdk Proxy动态生成一个代理类对象proxy。
注意Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader
:指定当前目标对象(实现类)使用的类加载器,获取加载器的方法是固定的Class<?>[] interfaces
:指定目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler:
指定
动态处理器,
执行目标对象的方法时,会触发事件处理器的方法。- 就是说在调用getProxy方法,返回一个DAOInterface proxy ,然后用proxy调用例如add()方法,这只是jdk给你生成的代理类调用,所以调用的时候会被重写的invoke拦截,然后调用Method 就可以调用到被代理类的方法(实现 InvocationHandler接口重写的invoke方法)
Aop底层的实现就是用aop。例如 还是打日志的问题,crud方法都调 log方法不好。那log类实现一个接口,重写log方法。但如果log方法改名字了,又不好了。用动态代理,log类改就改吧,反正在动态代理类里面。我们只要调用动态代理类的getProxy方法就可以啦。被代理的类是在java运行的时候通过Proxy类动态生成的。(这个到时候问就说说,不问就讲讲动态代理,不用说aop是怎么用动态代理的)
https://www.cnblogs.com/cenyu/p/6289209.html
4、mvc模式
5、观察者模式
一般应用于对象一对多的情况下。当一个对象发生改变了,要通知其他对象。类似与消息的 发布和订阅。
在项目中,例如 定了火车票,然后需要发短信和记录日志。常规的话,需要在定了火车票的内部 也就是下面去处理发短信或者写日志,如果还有别的操作需要改代码,耦合性很高。
那可以分为几个步骤:
1、观察者首先都要实现一个接口,这样方便以统一的接口去管理观察者(接口中有个方法work,就是说被观察者改变了,观察者需要去做的事情)
2、被观察者 有个方法add,入参是接口,用于把所有的观察者放到一个list中去,好循环遍历去告诉观察者 我改变了。
还有个change方法,循环遍历list,去触发观察者的work方法
3、mian: 实例化观察者、被观察者。调用被观察者的add方法,把实现类都放到list中。然后在调用change方法,循环遍历去触发work方法去执行 因为对象改变所触发的后续方法。
https://blog.csdn.net/zhangxiaomin1992/article/details/55511396?locationNum=11&fps=1
代码看这个:https://blog.csdn.net/wu_ming0821/article/details/51838078
顺便说一下封装:
封装可以理解为一层安全屏障,例如javabean中,set方法。你要set就得按照我说的数据格式来,不然校验不通过我就不给你set。并且你把一个方法封装起来,这个方法就实现这个功能,我随便改自己的这个方法,别人只要调用就行,不需要改代码。