# Java设计模式

Java设计模式

目标

  1. 学习反射技术,掌握反射的基本概念
  2. 着重学习全书的重点——动态代理和责任链模式,以及拦截器概念
  3. 掌握观察者模式
  4. 掌握工厂和抽象工厂模式
  5. 掌握Builder (构建)模式

学习反射技术,掌握反射的基本概念

Java反射技术应用广泛,它能够配置:类的全限定名,方法和参数,完成对象的初始化,甚至是反设莫些方法

通过反射构建对象

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectServiceImpl {
    public void sayHello(String name) {
        System.err.println("Hello " + name);
    }

}

反射生成对象

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ReflectTest reflectTest = new ReflectTest();
        System.out.println(reflectTest.getInstance());
        
    }   
public ReflectServiceImpl getInstance() {
        ReflectServiceImpl object = null;
        try {
            object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
                    .newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            ex.printStackTrace();
        }
        return object;
    }
}

运行代码将实例化,返回结果

com.lean.ssm.chapter2.reflect.ReflectServiceImpl@15db974

更改反射生成对象,使其参数赋值

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ReflectTest reflectTest = new ReflectTest();
        System.out.println(reflectTest.getInstance());
        
    }   
public ReflectServiceImpl getInstance() {
        ReflectServiceImpl object = null;
        try {
            object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
                    .newInstance();
            object.sayHello("张武");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            ex.printStackTrace();
        }
        return object;
    }
}

运行代码将实例化,返回结果

Hello 张武
com.lean.ssm.chapter2.reflect.ReflectServiceImpl@15db9742

完整代码

ReflectServiceImpl.java

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectServiceImpl {
    public void sayHello(String name) {
        System.err.println("Hello " + name);
    }

}

ReflectServiceImpl2.java

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;

public class ReflectServiceImpl2 {
    private String name;

    public ReflectServiceImpl2(String name) {
        this.name = name;
    }

    public void sayHello() {
        System.err.println("hello " + name);
    }
    
    public ReflectServiceImpl2 getInstance() {
        ReflectServiceImpl2 object = null;
        try {
            object = 
                (ReflectServiceImpl2) 
                Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl2").
                getConstructor(String.class).newInstance("张三");
        } catch (ClassNotFoundException | InstantiationException 
                    | IllegalAccessException | NoSuchMethodException 
                    | SecurityException | IllegalArgumentException 
                    | InvocationTargetException ex) {
                ex.printStackTrace();
        }
        return object;
    }
}

ReflectTest.java

ReflectServiceImpl target = new ReflectServiceImpl();

等于object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
.newInstance();

package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ReflectTest reflectTest = new ReflectTest();
        System.out.println(reflectTest.getInstance());
//      System.err.println(reflectTest.reflectMethod());
//      System.out.println(reflectTest.reflect());
        
    }
    
    public ReflectServiceImpl getInstance() {
        ReflectServiceImpl object = null;
        try {
            object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
                    .newInstance();
            object.sayHello("张武");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            ex.printStackTrace();
        }
        return object;
    }

    public Object reflectMethod() {
        Object returnObj = null;
        ReflectServiceImpl target = new ReflectServiceImpl();
        try {
            
            Method method = ReflectServiceImpl.class.getMethod("sayHello", String.class);
            returnObj = method.invoke(target, "张三");
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException ex) {
            ex.printStackTrace();
        }
        return returnObj;
    }

    public Object reflect() {
        ReflectServiceImpl object = null;
        try {
            object = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl")
                    .newInstance();
            Method method = object.getClass().getMethod("sayHello", String.class);
            method.invoke(object, "张三");
        } catch (NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException | InstantiationException ex) {
            ex.printStackTrace();
        }
        return object;
    }

}

着重学习全书的重点——动态代理和责任链模式,以及拦截器概念

动态代理:动态代理的意义在于生成一个占位(又称代理对象),来代理真是对象,从而控制真实的对象的访问。

代理必须分为两个步骤:

  • 代理对象和正式对象建立代理关系
  • 实现代理对象的代理逻辑方法

JAVA中有多种代理技术,比如JDK,CGLIB,Javassist,ASM,其中最常用的JDK,CGLIB。

JDK动态代理

JDK动态代理是java.lang.reflect.提供的方式。它必须借助一个接口才能产生代理对象,所以先定义接口。*

package com.lean.ssm.zw.proxy;

public interface HelloWorld {
    public void sayHelloWorld();
}

然后实习这些接口

package com.lean.ssm.zw.proxy;

public class HelloWorldImpl implements HelloWorld {

    @Override
    public void sayHelloWorld() {
        // TODO Auto-generated method stub
        System.out.println("Hello World");
    }

}

实现了最简单的java接口和实现来的关系,下面开始实现动态代理,

先建立代理对象和正式对象建立代理关系,后实现代理对象的代理逻辑方法

在JDK动态代理中,要实现逻辑类必须去实现java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于挂在代理对象。

package com.lean.ssm.zw.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyExcample implements InvocationHandler {
    private Object target=null;
    
    public Object bind(Object target) {
    
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("进入代理方法");
        System.out.println("在调度真实对象之前的服务");
        Object object =method.invoke(target, args);
        System.out.println("在调度真实对象之后的服务");
        return object;
    }

}

package com.lean.ssm.zw.proxy;



public class ProxyText {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        testJdkProxy1();
    }
    
    
    public static void testJdkProxy1() {
        JdkProxyExcample jdk=new JdkProxyExcample();
        HelloWorld proxy= (HelloWorld) jdk.JdkProxyExcample(new HelloWorldImpl());
        proxy.sayHelloWorld();
    }
}

CGLIB第三方动态代理(优点不需要提供接口,只要一个抽象类)(jar 包)(asm.jar,cglib.jar)

ReflectServiceImpl

package com.zw.proxyCGLiB;

public class ReflectServiceImpl {
    public void sayHello(String name) {
        System.out.println("Hello "+name);
        
    }
}

CglibProxyExample

package com.zw.proxyCGLiB;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxyExample implements MethodInterceptor {
    /**
     * 生成CGLIB对象
     * @param cls ——Class类
     * @return Class类的CGLIB代理对象
     */
    public Object getProxy(Class cls) {
// CGLIB enhancer 增强类对象
        Enhancer enhancer =new Enhancer();
//      设置增强类型
        enhancer.setSuperclass(cls);
//      定义代理逻辑对象为当前对象,要求当前对象实现MethodIntercepoter方法
        enhancer.setCallback(this);
//      生成并返回代理对象
        return  enhancer.create();
        
    }
    /**
     * 代理逻辑方法
     * @param proxy 代理对象
     * @param methd 方法
     * @param agrs 方法参数
     * @param metthodsProxy 方法代理
     * @return throwable 异常
     */

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("调用真实对象前");
//      CGLIB反射调用真实对象方法
        Object result =methodProxy.invokeSuper(proxy, args);
        System.err.println("调用真实对象之后");
        return result;
    }

}

调用方法

package com.zw.proxyCGLiB;



public class ProxyTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        tesCGLIBProxy();
    }
    public static void tesCGLIBProxy() {
        CglibProxyExample cpe=new CglibProxyExample();
        ReflectServiceImpl obj=(ReflectServiceImpl)cpe.getProxy(ReflectServiceImpl.class);
        obj.sayHello("12");

    }
}

Java异常处理

Exception in thread "main" java.lang.NoClassDefFoundError: org/objectweb/asm/Type
    根据java.lang.NoClassDefFoundError,可知缺少class 依赖,请百度“Exception in thread "main" java.lang.NoClassDefFoundError: org/objectweb/asm/Type” ,可知缺少asm.jar,请在浏览器上下载
        “asm.jar 下载”. 安装jar包,运行程式,


拦截器概念

由于动态代理一般都是比较难理解,程序设计者设计一个拦截器接口供开发者使用,开发者只要知道拦截器接口的方法,含义和作用即可,无需知道动态代理是怎么实现的,用JDK动态代理来实现一个拦截器接口Interceptor

package com.zw.intercept;

public interface HelloWorld {
    public void sayHelloWorld();
}

package com.zw.intercept;

public class HelloWorldImpl implements HelloWorld {

    @Override
    public void sayHelloWorld() {
        // TODO Auto-generated method stub
        System.out.println("Hello World");
    }

}

package com.zw.intercept;

import java.lang.reflect.Method;

public interface Interceptor {
    public boolean before(Object proxy, Object target, Method method, Object[] args);

    public void around(Object proxy, Object target, Method method, Object[] args);

    public void after(Object proxy, Object target, Method method, Object[] args);
}

这里定义了3个方法,before around after

3个方法的参数为:proxy代理对象,target真实对象, method方法,args 运行方法参数

package com.zw.intercept;

import java.lang.reflect.Method;

public class MyInterceptor implements Interceptor {
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("反射方法前逻辑");
        return false;// 不反射原有的方法
    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("反射方法后逻辑");
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("取代了被代理对象的方法");
    }
}


它实现了所有的Interceptor接口方法

package com.zw.intercept;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InterceptorJdkProxy implements InvocationHandler {

    private Object target; //真实对象
    private String interceptorClass = null;//拦截器全限定名
    
    public InterceptorJdkProxy(Object target, String interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }

    /**
     * 绑定委托对象并返回一个代理占位
     *
     * @param target 真实对象
     * @return 代理对象占位
     */
    public static Object bind(Object target, String interceptorClass) {
        //取得代理对象    
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), 
                new InterceptorJdkProxy(target, interceptorClass));
    }

    @Override
    /**
     * 通过代理对象调用方法,首先进入这个方法
     *
     * @param proxy --代理对象
     * @param method --方法,被调用方法
     * @param args -- 方法参数
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (interceptorClass == null) {
            //没有设置拦截器则直接返回原有的方法
            return method.invoke(target, args);
        }
        Object result = null;
        //ͨ通过反射生成拦截器
        Interceptor interceptor = 
            (Interceptor) Class.forName(interceptorClass).newInstance();
        //调用前置方法
        if (interceptor.before(proxy, target, method, args)) {
            //反射原有对象方法
            result = method.invoke(target, args);
        } else {//返回false执行around方法
            interceptor.around(proxy, target, method, args);
        }
        //调用后置方法
        interceptor.after(proxy, target, method, args);
        return result;
    }
}
package com.zw.intercept;

import java.lang.reflect.Method;

public class MyInterceptor implements Interceptor {
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("反射方法前逻辑");
        return false;//  不反射原有的方法
    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("反射方法后逻辑");
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.err.println("取代了被代理对象的方法");
    }
}

package com.zw.intercept;

import com.zw.intercept.InterceptorJdkProxy;

import com.zw.intercept.*;

public class TestInterceptor {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        testInterceptor();
        testChain();
    }
    public static void testInterceptor() {
        HelloWorld proxy =(HelloWorld)InterceptorJdkProxy.bind(new HelloWorldImpl(), 
                "com.zw.intercept.MyInterceptor");
        proxy.sayHelloWorld();
        
    }
    public static void testChain() {
        HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(
                new HelloWorldImpl(), "com.zw.intercept.Interceptor2");
        proxy1.sayHelloWorld();
        
    }
}

责任链模式

public static void testChain() {
        HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(
                new HelloWorldImpl(), "com.lean.ssm.chapter2.intercept.Interceptor1");
        HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(
                proxy1, "com.lean.ssm.chapter2.intercept.Interceptor2");
        HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(
                proxy2, "com.lean.ssm.chapter2.intercept.Interceptor3");
        proxy3.sayHelloWorld();
    }
testChain() 责任链

责任链模式:优点:在于我们可以在传递链上加入新的拦截器。

                    缺点:是会增加代理和反射,而代理和反射的性能不高。

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者观察多个被观察者对象的状态,当被观察的状态发送变化时,会通知所有观察者,并让其自动更新自己。在java中 java.util.Observable

观察者

package com.lean.ssm.chapter2.observer;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

public class ProductList extends Observable {
    
    private List<String> productList = null;//产品列表
    
    private static ProductList instance;//类的唯一实例
    
    private ProductList() {}//构建方法私有化
    
    /**
     * 取得唯一实例
     * @return 产品列表唯一实例
     */
    public static ProductList getInstance() {
        if (instance == null) {
            instance = new ProductList();
            instance.productList = new ArrayList<String>();
        }
        return instance;
    }
    
    /**
     * 增加观察者(电商接口)
     * @param observer 观察者
     */
    public void addProductListObserver(Observer observer) {
        this.addObserver(observer);
    }
    
    /**
     *  新增产品
     * @param newProduct 新产品 
     */
    public void addProudct(String newProduct) {
        productList.add(newProduct);
        System.err.println("產品列表心增了產品"+newProduct);
        this.setChanged();//设置被观察对象发生变化
        this.notifyObservers(newProduct);//通知观察者,并传递新产品
    }
}

这个类的基本内容和主要用法

  • 构建方法私有化,避免通过new的方式创建对象,而是通过getInstance 方法获得产品列表单例,这里使用的是单例模式。
  • addProductListObserver 可以增加一个电商接口(观察者)。
  • 核心逻辑在addProduct方法上,在产品列表上增加了一个新的产品,然后调用setChanged方法。这个方法用于告知观察者当前被观察者发生了变化,如果没有,则无法触发其行为,最后通过notifyObservers告知观察者,让它们发送相应的动作,并将新产品为参数传递给观察者。

观察者

package com.lean.ssm.chapter2.observer;

import java.util.Observable;
import java.util.Observer;

public class JingDongObserver implements Observer {
    @Override
    public void update(Observable o, Object product) {
        String newProduct = (String) product;
        System.err.println("發送新產品"+newProduct+"同步到金東");
    }
}

package com.lean.ssm.chapter2.observer;

import java.util.Observable;
import java.util.Observer;

public class TaoBaoObserver implements Observer {

    @Override
    public void update(Observable o, Object product) {
        String newProduct = (String) product;
        System.err.println("發送新產品"+newProduct+"淘寶商城");
    }    
}

package com.lean.ssm.chapter2.observer;

public class ObserverTest {
    
    public static void main(String[] args) {
        ProductList observable = ProductList.getInstance();
        TaoBaoObserver taoBaoObserver = new TaoBaoObserver();
        JingDongObserver jdObserver = new JingDongObserver();
        observable.addObserver(jdObserver);
        observable.addObserver(taoBaoObserver);
        observable.addProudct("新增產品1");
    }
}

掌握工厂抽象工厂模式

抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象

掌握Builder (构建)模式

package com.lean.ssm.chapter2.builder;

public class TicketBuilder {
    public static Object builder(TicketHelper helper) {
        System.out.println("ͨ通过TicketHelper构建套票信息");
        return null;
    }
}

package com.lean.ssm.chapter2.builder;

public class TicketHelper {

    public void buildAdult(String info) {
        System.err.println("构建成人票逻辑" + info);
    }

    public void buildChildrenForSeat(String info) {
        System.err.println("构建有座儿童票逻辑" + info);
    }

    public void buildchildrenNoSeat(String info) {
        System.err.println("构建无座儿童票逻辑" + info);
    }

    public void buildElderly(String info) {
        System.err.println("构建有老人票逻辑" + info);
    }

    public void buildSoldier(String info) {
        System.err.println("构建军人及其家属逻辑" + info);
    }
}

package com.lean.ssm.chapter2.builder;

public class BuilderTest {
    public static void main(String[] args) {
        TicketHelper helper = new TicketHelper();
        helper.buildAdult("成人票");
        helper.buildChildrenForSeat("有座儿童票");
        helper.buildchildrenNoSeat("无座儿童票");
        helper.buildElderly("老人票");
        helper.buildSoldier("军人票");
        Object ticket = TicketBuilder.builder(helper);
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,099评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,828评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,540评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,848评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,971评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,132评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,193评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,934评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,376评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,687评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,846评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,537评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,175评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,887评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,134评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,674评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,741评论 2 351

推荐阅读更多精彩内容