原创

Java利用反射来实现简单工厂模式和代理模式

工厂模式和代理模式是java的23种设计模式中比较重要和常见的设计模式,借着学习反射机制的同时来练习下如何实现这两种设计模式:

参考博文:
http://www.cnblogs.com/lzq198754/p/5780331.html
http://blog.csdn.net/jackiehff/article/details/8621517

简单工厂模式

  • 抽象产品角色
package lesson6;

/**
 * 测试用接口
 * 只有一个方法eat
 * @author xuwangcheng
 *
 */
public interface Fruit {
    void eat();
}
  • 具体产品角色
package lesson6;

public class Apple implements Fruit{

    private String name = "苹果";
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("正在吃" + name);
    }

}
package lesson6;

public class Cherry implements Fruit{

    private String name = "樱桃";
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("正在吃" + name);
    }

}
  • 工厂类角色
package lesson6;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 由于接口Fruit可能有无数个实现类
 * 在客户端如果要调用新增实现类的eat方法:
 * 1、不使用工厂模式:客户端在接收不同的参数的时候进行判断,然后根据参数名客户端自己创建不同
 *     实现类的实例,在实现类不断增加的情况下,可能需要同时不断的修改客户端代码;
 * 2、不使用反射的工厂模式:客户端将判断参数的步骤交给工厂类去完成,工厂类根据传入的参数新建不同的对应的实现类
 *     的实例,然后返回给客户端,在实现类不断增加的情况下,只需要更改工厂类的代码即可;
 * 3、使用反射的工厂模式:工厂方法根据传入的名称取指定配置文件中对应的类的完整的包名和类名,通过反射获取对应实现类
 *     的实例返回给客户端,在实现类不断增加的情况下,只需要修改配置文件就行了
 * @author xuwangcheng
 *
 */
public class FruitFactory {

    public static Fruit getInstance(String name) {
        Fruit f = null;
        try {
            f = (Fruit) Class.forName(getProperties(name)).newInstance();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return f;
    }

    public static String getProperties(String name) throws IOException {
        Properties p = new Properties();
        InputStream inputStream = FruitFactory.class.getClassLoader()
                   .getResourceAsStream("my.properties");          
        p.load(inputStream);
        return p.getProperty(name);
    }
}
  • 测试代码
    my.properties
    apple=lesson6.Apple
    cherry=lesson6.Cherry
    
package lesson6;

/**
 * 简单工厂模式
 * 又称静态工厂方法模式,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化。
 * 主要包含下面:
 * 1、工厂类角色:本例中的FruitFactory,含有一定的逻辑和业务,决定根据条件来实例化某一个对象
 * 2、抽象产品角色:本例中的Fruit,可能是接口或者抽象类,由具体的产品来实现或者继承
 * 3、具体产品角色:本例中的Apple和Cherry,具体继承或者实现抽象产品,工厂类角色创建的对象实例。
 * @author xuwangcheng
 *
 */
public class Test {
    public static void main(String[] args) {
        Fruit f1 = FruitFactory.getInstance("apple");
        Fruit f2 = FruitFactory.getInstance("cherry");
        f1.eat();
        f2.eat();
    }
}

代理模式

  • 抽象主题角色
package lesson7;

/**
 * 抽象主题角色
 * @author xuwangcheng
 *
 */
public interface Subject {
    void work(String name);
    String sleep();
}
  • 具体主题角色
package lesson7;

/**
 * 具体主题角色
 * @author xuwangcheng
 *
 */
public class RealSubject implements Subject{

    @Override
    public void work(String name) {
        // TODO Auto-generated method stub
        System.out.println("正在工作..." + name);
    }

    @Override
    public String sleep() {
        // TODO Auto-generated method stub
        return "在睡觉";
    }


}
  • 代理角色

通过动态代理类来生成

package lesson7;

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


/**
 * 通过继承InvocationHandler接口来实现动态代理(反射)
 * 如果按照普通模式来实现代理模式的话,针对不同的抽象主题则需要创建不同的代理类
 * 而通过反射机制来实现,通过传入不同的具体主题角色的实例来创建对应的代理角色
 * @author xuwangcheng
 *
 */
public class MyProxy implements InvocationHandler{

    private Object obj;

    //私有化构造器
    private MyProxy(Object obj) {
        super();
        this.obj = obj;
    }

    /**
     * 创建代理对象
     * @param obj  具体主题对象的实例
     * @return
     */
    public static Object getInstance(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyProxy(obj));
    }

    /**
     * 代理对象在需要执行抽象主题的某个方法时,通过调用method.invoke方法,同时将
     *     真实主题角色实例和这个方法需要的参数传递进去,执行得到结果。
     *     在method.invoke(obj, args)的前后就能创建自定义的前置或者后置处理方法。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result = null;
        try {
            System.out.println(method.getName() + "预处理:马上开始执行...");
            result = method.invoke(obj, args);
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            System.out.println("代理处理出现错误:" + e.getMessage());
        } finally {
            System.out.println(method.getName() + "收尾处理:执行好了...");
        }        
        return result;
    }


}

测试代码

package lesson7;


/**
 * 代理模式
 * 创建一个代理对象,该对象在不改变目标对象(真实对象)的所有功能实现的前提下对其进行控制,
 *     并且可以添加一些额外的功能(比如添加方法的前置处理和后置处理)
 * 包含下面:
 * 1、抽象主题角色:本例中的Subject,可以是抽象类或者接口
 * 2、具体主题角色:本例中的RealSubject,真实对象,业务逻辑的具体执行
 * 3、代理角色: 本例中由MyProxy的getInstance来生成,具体主题角色 的委托,由它将抽象主题角色中的抽象方法交给具体主题角色来完成,
 *     在具体角色处理完成的前后进行预处理和善后。
 * @author xuwangcheng
 *
 */
public class Test {
    public static void main(String[] args) {
        Subject s = new RealSubject();
        Subject sp = (Subject) MyProxy.getInstance(s);
        sp.work("好吧");
        System.out.println(sp.sleep());
    }
}
正文到此结束