1.首先来看最普通的工厂模式
1.1 定义一个需要工厂生产的java类
package javaee.net.cn.factory; class Person{ private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [age=" + age + ", name=" + name + "]"; } }
1.2 写一个最普通的工厂
package javaee.net.cn.factory; import org.junit.Test; public class BeanFactory { @Test public void test() throws Exception{ Person person = createPerson(); System.out.println(person.toString()); } public static Person createPerson(){ return new Person(); } }
上面的是最普通的工厂模式,不过使用new关键字来创建的对象,如果代码中出现很多这种new的代码(POJO除外)
那么 这种非常不容易维护和扩展。
2.对工厂模式优化 -->反射工厂
package javaee.net.cn.factory; import org.junit.Test; public class BeanFactory { @SuppressWarnings("unchecked") public static <T> T getBean(String className,Class<T> Type) throws Exception{ Class<T> clz = (Class<T>) Class.forName(className); Object obj = clz.newInstance();//进行实例化操作,要求类中必须存在无参的构造方法 if(!Type.isInstance(obj)){ throw new Exception("对象和内容不兼容"); } return (T)obj; } @Test public void test() throws Exception{ Person person = getBean("javaee.net.cn.factory.Person",Person.class); System.out.println(person.toString()); } }
Tip:getBean是一个泛型方法,可以在编译期间检查所要传入的对象和想要获取的对象是否一致
反射工厂虽然没有了虽然对普通工厂有一些改善(避免了new关键字)但是还是出现了硬编码"javaee.net.cn.factory.Person"
3.利用Annotation改善反射工厂
3.1先定义一个注解@FactoryFlag
package javaee.net.cn.factory.strategy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface FactoryFlag { // 定义一个Annotation public String className();//定义一个className()属性 }
3.2把注解应用到BeanFactory
package javaee.net.cn.factory; import javaee.net.cn.factory.strategy.FactoryFlag; import org.junit.Test; @FactoryFlag(className="javaee.net.cn.factory.Person") public class BeanFactory { @SuppressWarnings("unchecked") public static <T> T getBean(String className,Class<T> Type) throws Exception{ Class<T> clz = (Class<T>) Class.forName(className); Object obj = clz.newInstance();//进行实例化操作,要求类中必须存在无参的构造方法 if(!Type.isInstance(obj)){ throw new Exception("对象和内容不兼容"); } return (T)obj; } @Test public void test() throws Exception{ Class<?> cls = BeanFactory.class; FactoryFlag factoryFlag = cls.getAnnotation(FactoryFlag.class); String className = factoryFlag.className(); Person person = BeanFactory.getBean(className,Person.class); System.out.println(person.toString()); } }
这样 我们的代码里面就没有硬编码了 而是写在了注解上,@FactoryFlag(className="javaee.net.cn.factory.Person")
当然 也可以写在配置文件里,然后读进来,我们在这里是写在注解上 然后去读取注解
里面用到的一些放射方法(获取注解、创建对象) 大家可以去参考JDK的API
上面的Demo Bean工厂只生产了一个对象,其实:工厂可以生产一系列对象(这才叫工厂吗)
这样 我们替换工厂的时候 可以直接替换掉那一系列对象,工厂也可以利用多态 写成抽象工厂