zoukankan      html  css  js  c++  java
  • 【Java反射机制】用反射改进简单工厂模式设计

      如果做开发的工作,工厂设计模式大概都已经深入人心了,比较常见的例子就是在代码中实现数据库操作类,考虑到后期可能会有数据库类型变换或者迁移,一般都会对一个数据库的操作类抽象出来一个接口,然后用工厂去获取实际数据库操作类实例。

      下面举一个最简单的工厂模式例子:

    interface IAnimal {
        void talk();
    }
    class Cat implements IAnimal {
        @Override
        public void talk() {
            System.out.println("I'm cat");
        }
    }
    class Dog implements IAnimal {
        @Override
        public void talk() {
            System.out.println("I'm dog");
        }
    }
    class AnimalFactory {
        private AnimalFactory() {}
        public static IAnimal getInstance(String animal) {
            if ("Cat".equals(animal)) {
                return new Cat();
            } else if ("Dog".equals(animal)) {
                return new Dog();
            } else {
                return null;
            }
        }
    }
    public class Main {
        public static void main(String[] args) throws ParseException{
            IAnimal animal = AnimalFactory.getInstance("Cat");
            animal.talk();
            animal = AnimalFactory.getInstance("Dog");
            animal.talk();
        }
    }
    View Code

      最简洁的例子了, 客户端首先想要生成一个Cat的实例,传入“Cat”,一阵操作之后,又想生成Dog实例,直接传入“Dog”到工厂里面拿,接着继续使用。

      观察工厂类,里面是根据客户端传过来的字符串手动new一个实例并返回,那如果这个工厂刚好要容纳好几百种实例的返回,并可能会不定时添加新的实例类型,那岂不是每次都要去修改工厂类,有没有一个办法我写一次工厂类,然后工厂类能自动产生并返回客户端需要的实例? 这个时候我们可以利用反射的机制,根据客户端传进来的字符串,运用反射原理去寻找我们所要的实体类。首先呢,接口和实体类都要写还给他的,接着呢修改工厂类如下:

    class AnimalFactory {
        private AnimalFactory() {}
        public static IAnimal getInstance(String animal) {
            try {
                Class cls = Class.forName(animal);
                return (IAnimal) cls.newInstance();
            } catch (Exception e) {
                return null;
            }
        }
    }
    View Code

    首先由Class类型的静态方法forName(String className)找到这个类并返回这个类的Class类型对象, 此时找不到的话会抛出ClassNotFoundException,抛出异常了就返回null咯。

    然后用Class对象的newInstance()方法产生一个实例,这个实例就是forName函数找到的实体类实例。相当于用默认构造函数产生一个实例,所以此处也会抛出异常,比如默认构造函数是私有类型的情况下。

    接着,如果我产生的实例都需要根据传入的参数对应去实例化呢,这个时候,我们可以利用反射去找有相应参数的构造函数,再生成一个实例就好啦。

    interface IAnimal {
        void talk();
    }
    class Cat implements IAnimal {
        private String name;
        public Cat(String name) {
            this.name = name;
        }
        @Override
        public void talk() {
            System.out.println("I'm cat:" + this.name);
        }
    }
    class Dog implements IAnimal {
        private String name;
        public Dog(String name) {
            this.name = name;
        }
        @Override
        public void talk() {
            System.out.println("I'm dog:" + this.name);
        }
    }
    class AnimalFactory {
        private AnimalFactory() {}
        public static IAnimal getInstance(String animal, String name) {
            try {
                Class cls = Class.forName(animal);
                Constructor<?> con = cls.getConstructor(String.class);
                return (IAnimal)con.newInstance(name);
            } catch (Exception e) {
                return null;
            }
        }
    }
    public class Main {
        public static void main(String[] args) throws ParseException{
            IAnimal animal = AnimalFactory.getInstance("Cat", "Miao");
            animal.talk();
            animal = AnimalFactory.getInstance("Dog", "Wang");
            animal.talk();
        }
    }
    View Code

    在工厂类中,我们如果找到这个类的Class类型对象时,就用这个Class对象去找对应的Constructor对象,getConstructor方法接受无数个参数,根据需要指定我们要找的这个构造函数参数类型是什么,例子中这个类型是String,所以我们用String.class去指定这个类型便是String类型,接着用这个Constructor对象,newInstance(String para)实例化并返回。

    至此,用反射改进传统工厂模式步骤完成。 如有写的不妥之处,欢迎之处斧正。

    尊重知识产权,转载引用请通知作者并注明出处!

  • 相关阅读:
    Self Numbers
    【acdream】小晴天老师系列——竖式乘法
    全错位排列
    2 ^ x mod n = 1问题
    基于cocos2dx的横版动作游戏制作(二)
    基于cocos2dx的横版动作游戏制作(一)
    横版游戏制作之英雄技能CD遮罩,人物头像血条属性
    cocos2d横版游戏之摇杆控制
    C++ delete []p 数组指针,如何知道该数组大小的
    do { ....} while(0) 在宏里冗余的意义
  • 原文地址:https://www.cnblogs.com/GNLin0820/p/8674921.html
Copyright © 2011-2022 走看看