设计模式基础
选择恰当的设计模式可以大大提高代码质量,可以说是优秀程序员编程智慧的产物。设计模式巧妙运用java基础知识:
- 多态:动态绑定
。。。(待补充,觉得最核心的就是多态)
单例模式
- 本质:确保类的实例化对象有且仅有一个
- 应用:配置文件、日志、缓存、线程池等
- 优点:避免过多占用资源或者数据同步问题
分类:
饿汉模式:静态化实例跟随类一同加载,无论是否在外部创建实例
step1:实例由构造方法创建,故改写构造方法(public -> private)
确保外部不能随意调用
step2:创建用于返回的私有静态实例,静态确保了唯一性
step3:返回实例的getInstance( )方法懒汉模式:只是声明静态实例,只有当用户获取时才判断并创建实例
step1:构造方法私有化
step2:声明类的唯一实例
step3:获取实例方法
区别:
是否在内部进行实例化
工厂模式
- 目的:实现对象间的低耦合
- 特点:
对象的创建由工厂负责
客户类产品成员面向接口,通过多态获取各工厂的产品
可以按照需求指定特定工厂来生产产品 - 技术支持:
反射,class Properties/File.properties - 简单工厂模式:
所有的产品均由一个工厂生产,根据客户端要求生产出特定的产品,其缺点就是大大增加了工厂类的负担
class Factory{
public Product getProduct1(){
return new Product1();
}
public Product getProduct2(){
return new Product2();
}
}
- 抽象工厂模式:
- 产品:接口派生出各类产品
eg : class Product1 implements Product
class Product2 implements Product - 工厂:接口派生出用于生产各类产品的工厂
- 产品:接口派生出各类产品
interface ProductFactory{
public Product getProduct();
}
class Product1Factory implements ProductFactory{
@override
public Product getProduct(){
return new Product1();
}
}
class Product1Factory implements ProductFactory{
@override
public Product getProduct(){
return new Product2();
}
}
3.客户:创建工厂获得产品
eg:Product p = Product1Factory.getProduct( );
观察者模式
使用场景:
对象间存在依赖关系(理解成星型依赖)当 中心变化时需要其余周围对象及时更新自己。最近学习MQTT协议感觉观察者模式比较适用。使用方法:
观察者://更新方法: public void update()
被观察者:
//维护一个观察者列表 private List<Watcher> watcherList = new ArrayList<Watcher>(); //添加观察者方法 public void addWatcher(Watcher watcher); //删除观察者方法 public void delWatcher(Watcher watcher); //通知观察者方法 public void notifyWatchers();
推拉方式
推方式:被观察者维护一个自己的状态(可以考虑JavaBean),当状态发生改变时主动将状态发送给观察者。适用于被观察者比较复杂,观察者必须获得一些信息的情况。
拉模式:观察者主动从被观察者处获得状态,只是被观察者需要提供一个状态获取接口。使用java.util.Observable和java.util.Observer
//源码不多,直接粘过来
public class Observable
{
private boolean changed = false;
private Vector<Observer> obs = new Vector();
public synchronized void addObserver(Observer paramObserver)
{
if (paramObserver == null) {
throw new NullPointerException();
}
if (!obs.contains(paramObserver)) {
obs.addElement(paramObserver);
}
}
public synchronized void deleteObserver(Observer paramObserver)
{
obs.removeElement(paramObserver);
}
public void notifyObservers()
{
notifyObservers(null);
}
public void notifyObservers(Object paramObject)
{
Object[] arrayOfObject;
synchronized (this)
{
if (!changed) {
return;
}
arrayOfObject = obs.toArray();
clearChanged();
}
for (int i = arrayOfObject.length - 1; i >= 0; i--) {
((Observer)arrayOfObject[i]).update(this, paramObject);
}
}
public synchronized void deleteObservers()
{
obs.removeAllElements();
}
protected synchronized void setChanged()
{
changed = true;
}
protected synchronized void clearChanged()
{
changed = false;
}
public synchronized boolean hasChanged()
{
return changed;
}
public synchronized int countObservers()
{
return obs.size();
}
}
public abstract interface Observer
{
public abstract void update(Observable paramObservable, Object paramObject);
}
代理模式
代理十分好理解就是代替被代理的对象完成一些行为,类比现实生活中的销售代理,就是为厂家去销售产品,而不是只有厂家直销一种方式。
厂家: 我们映射为被代理对象、真实对象。
销售代理: 我们映射为代理对象,它具有真实对象的行为,即有相同的接口实现。
粗糙例子一个:
厂家授权代理负责产品的销售(实现相同接口)
代理按照厂家吩咐对外有定价(接口中具体实现比厂家更细致)
代理下单,厂家发货(最终仍然使用厂家的接口实现)
/*
* sell product interface
*/
public interface sellProduct(){
public void sell();
}
/*
* factory
*/
public class Factory implements sellProduct{
@Override
public void sell(){
System.out.println("sell a product");
}
}
/*
* proxy
*/
public class Proxy implements sellProduct{
private double price;
//real object
private Factory factory;
public Factory getFactory() {
return factory;
}
public void setFactory(Factory factory) {
this.factory = factory;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public void sell(){
if(price >= 9999)
factory.sell();
else if(price > 0 && price < 9999)
System.out.println("cannot afford");
else
System.out.println("don't joke me");
}
}
/*
* deal
*/
public static void main(Stirng[] args){
Proxy proxy = new Proxy();
Factory factory = new Factory();
proxy.setFactory(factory);
proxy.setPrice(9999);
proxy.sell();
}
动态代理模式
在代理模式的基础之上运用反射技术。
当前常用的动态代理模式是JDK动态代理和CGLIB动态代理
JDK使用过程很简便:
- 实现java.lang.reflect.InvocationHandler
- 建立代理对象和真实对象之间的关系
private real object;
bind( ); - 实现代理逻辑方法:
invoke( );
简单粗糙例子一个,只列出以上三步:
public class JDKProxy implements InvocationHandler {
// real object
private Object target;
/*
* step1: create relation between proxy object and real object
*
* @param real object
*
* @return proxy object
*/
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/*
* step2: proxy method
* @param proxy object
* @param method
* @param arguments
* @return proxy result
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("enter into proxy logical method");
System.out.println("before invoke real object");
Object obj = method.invoke(target, args);
System.out.println("after invoke real object");
return obj;
}
}
CGLIG动态代理
与JDK类似但是不同之处在于JDK代理的类必须实现接口,而CGLIB则是通过生成被代理类的子类,通过增强方法覆盖父类方法
- 增强方法获得被代理对象,以被代理类为父类。
- 实现代理逻辑方法
简单粗糙例子
public class CGLIBProxy implements MethodInterceptor {
public Object getProxy(Class realObject) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(realObject);
enhancer.setCallback(this);
return enhancer.create();
}
/*
* implements logical proxy method
*
* @param proxy object
*
* @param method????
*
* @param method arguements
*
* @param proxy method
*
* @return result
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before call real object");
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("after call real object");
return result;
}
}
适配器模式
实践出真知,经历的积累就会形成一个人阅历,对待事物有不同深度的理解。
对适配器模式的学习理解,恰恰经历了马哲辩证法中知识与实践相互促进的过程(扯远了)
- 初识:适配器模式就像是视频线转换口,笔记本上只有HDMI口,而显示器只有VGA口,现在没有可以直接相连的线。所以需要淘一个东西把VGA的口“改造”一下,让笔记本以为显示器就是提供的HDMI插口,于是连接工作。
- 验证:初识只是举了一个形象的例子,算是将抽象的概念简单的形象化一下。实践中,才深刻体会到适配器模式的意义。
IC卡表向web应用迁移,将原有的MFC客户端的工作迁移到浏览器上,使用的仍然是厂家提供的操作库——原已有接口
浏览器通过ActiveX调用底层接口,ActiveX采用ATL开发生成dll,在该dll中调用库接口实现对外的接口——适配后目标接口
用户可以使用JS直接引入ActiveX,并使用新接口 - 强化初识认知,适配器模式两大要点:
- 用已有接口实现
- 实现适配接口
装饰器模式
和适配器模式类似,区别在于适配器模式按照需要改造接口,而装饰器模式保留接口原貌但是功能进行增强。