JAVA知识点全总结——(七)设计模式
7. 设计模式
7.1 单例模式
//线程安全,惰性加载
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}
public Singleton getInstence() {
if(singleton == null){
synchronized(Singleton.class){
if(singleton == null)
singleton = new Singleton();
}
}
return singleton;
}
}
7.2 代理模式
可以实现业务逻辑和额外逻辑的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
7.2.1 静态代理
若代理类在程序运行前就已经存在,那么这种代理方式称为静态代理,这种情况下的代理类通常都是我们在Java代码中定义的。静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。继承同一个类或者接口,实现同样的方法,代理类加上自己额外的操作,再调用目标类的同样的方法。可以产生代理对象的静态代理工厂类,封装两个类。
7.2.2 动态代理
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。
在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。
public class DynamicProxy implements InvocationHandler {
private Object obj; //obj为委托类对象;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args);
System.out.println("after");
return result;
}
}
7.3 装饰器模式
我们要买奶茶,希望加红豆和布丁。考虑如何实现这个对象的构造:
- 把红豆和布丁作为两个成员变量:无法动态的添加成员变量
- 创建一个成员变量表示“添加列表”,添加红豆和布丁作为元素:我们的奶茶需要一些修饰方法与红豆和布丁有关
- 红豆和布丁作为两个独立的类,继承奶茶:如果一杯奶茶既添加了红豆又添加了布丁则无法实现这种效果
可见普通的组合和继承都无法很好的实现我们的要求。此时可以使用装饰器模式。
Component为统一接口,也是装饰类和被装饰类的基本类型。 ConcreteComponent为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。 Decorator是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。 ConcreteDecorator是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。
7.4 工厂模式
7.4.1 静态工厂方法
静态工厂方法是指一些方法能够为我们创建一个新对象,通过创建对象时会进行不同的参数配置,但是我们无需关心,我们只需要调用相应的方法,方法名上会表示出此方法的作用。
7.4.2 简单工厂
简单工厂是指多个不同对象的创建封装在一个工厂方法里面,通过if-else的判断创建不同的对象。
7.4.3 工厂模式
简单工厂虽然简单易行,但是在我们需要广泛运用工厂方法,尤其是需要通过反射来创建不同对象的时候是有局限性的,而且简单工厂的代码重写率很高效果不好。创建多个工厂类,继承结构和我们要new的类的结构类似。各个工厂类中,都对应一个同名获得接口A实例的方法。用户决定使用哪个工厂。
7.4.4 抽象工厂
对工厂方法进行扩展。各个工厂类中,再增加一个获得接口B实例的方法。
7.4.5 为什么需要工厂方法?
工厂方法多加一层工厂封装类的意义在于:1、用户并不想关心产品接口是怎么实现的,如果这个实现过程和逻辑比较复杂呢?将这个过程封装到工厂类中,别的地方也可以重用;2、接口的具体怎么实现,全部交给另一个人去做(他写的产品类)。如果添加一个新产品,那么他再添加一个工厂类和产品类,用户使用这个工厂类即可。
工厂类可以继承于某个接口,或是抽象类,工厂类已经对产品类的实现就行了封装,用户用它结合配置参数和反射实现动态创建,是很合理的。相比简单工厂是不太合适的。代码底层,当产品类创建分支是固定或是其他类似的地方很少时,用简单工厂很合适。因为一旦增加分支,改的地方很少。如果不是,建议用工厂方法。抽象工厂和工厂方法没有本质区别,是对工厂方法的扩展。当产品类,涉及到多个产品簇时,需要对同类的产品抽象为一个接口。工厂类中,可以定义多个返回具体产品的方法,*组合。
7.5 策略模式
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。分析下定义,策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。
7.6 观察者模式
其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅能收到信息,分推和拉两种。
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
上一篇: Eclipse使用技巧——Java工具