设计模式--工厂模式

    将多个类对象交给工厂类来生成的设计方式被称为工厂模式,工厂类可以让系统具有更好的可维护性、可扩展性。

一、简单工厂模式实现

1. 定义一个 Computer 类,调用 Output 对象,将 Computer 类与Output 的实现类分离开来,只需面向Output接口编程即可。

package see;

public class Computer {
    private Output out;
    public Computer(Output out) {
        this.out = out;
    }
    // 定义一个模拟获取字符串输入的方法
    public void keyIn(String msg) {
        out.getData(msg);
    }
    // 定义一个模拟打印的方法
    public void print() {
        out.out();
    }
    public static void main(String[] args) {
        // 创建OutputFactory
        OutputFactory of = new OutputFactory();
        // 将Output对象传入,创建Computer对象
        Computer c = new Computer(of.getOutput());
        c.keyIn("轻量级Java EE企业应用实战");
        c.keyIn("疯狂Java讲义");
        c.print();
    }
}

2. 定义一个 OutputFactory 工厂类,负责产生Output实现类的实例。

package see;

public class OutputFactory {
    public Output getOutput() {
        // 下面两行代码用于控制系统到底使用Output的哪个实现类。
        // return new Printer();
        return new BetterPrinter();
    }
}

3. Output接口

package see;

public interface Output {
    // 接口里定义的属性只能是常量
    int MAX_CACHE_LINE = 50;
    // 接口里定义的只能是public的抽象实例方法
    void out();
    void getData(String msg);
}

4. Output实现类一Printer

package see;

//让Printer类实现Output
public class Printer implements Output {
    private String[] printData = new String[MAX_CACHE_LINE];
    // 用以记录当前需打印的作业数
    private int dataNum = 0;
    public void out() {
        // 只要还有作业,继续打印
        while (dataNum > 0) {
            System.out.println("打印机打印:" + printData[0]);
            // 把作业队列整体前移一位,并将剩下的作业数减1
            System.arraycopy(printData, 1, printData, 0, --dataNum);
        }
    }
    public void getData(String msg) {
        if (dataNum >= MAX_CACHE_LINE) {
            System.out.println("输出队列已满,添加失败");
        } else {
            // 把打印数据添加到队列里,已保存数据的数量加1。
            printData[dataNum++] = msg;
        }
    }
}

5. Output实现类二BetterPrinter

package see;

public class BetterPrinter implements Output {
    private String[] printData = new String[MAX_CACHE_LINE * 2];
    // 用以记录当前需打印的作业数
    private int dataNum = 0;
    public void out() {
        // 只要还有作业,继续打印
        while (dataNum > 0) {
            System.out.println("高速打印机正在打印:" + printData[0]);
            // 把作业队列整体前移一位,并将剩下的作业数减1
            System.arraycopy(printData, 1, printData, 0, --dataNum);
        }
    }
    public void getData(String msg) {
        if (dataNum >= MAX_CACHE_LINE * 2) {
            System.out.println("输出队列已满,添加失败");
        } else {
            // 把打印数据添加到队列里,已保存数据的数量加1。
            printData[dataNum++] = msg;
        }
    }
}

二、类似Spring IoC容器的工厂模式实现

1. 定义一个类似与Spring配置文件的配置文件bean.xml

<?xml version="1.0" encoding="GBK"?>
<beans>    
    <bean id="computer" class="test.Computer">
        <!-- 为out属性注入普通属性值 -->
        <property name="out" ref="betterPrinter"/>
    </bean>
    <!-- 配置两个Bean实例 -->
    <bean id="printer" class="test.Printer"/>
    <bean id="betterPrinter" class="test.BetterPrinter"/>
    <!-- 配置一个prototype行为的Bean实例 -->
    <bean id="now" class="java.util.Date" scope="prototype"/> <!--①-->
</beans>

2. 定义工厂类(需引入dom4j-1.6.1.jar解析配置文件)

接口ApplicationContext:

package test;
public interface ApplicationContext {
    // 获取指定Bean实例的方法
    Object getBean(String name) throws Exception;
}

实现类YeekuXmlApplicationContext:

package test;

import java.lang.reflect.*;
import java.util.*;
import java.io.*;
import org.dom4j.*;
import org.dom4j.io.*;

public class YeekuXmlApplicationContext implements ApplicationContext {
    // 保存容器中所有单例模式的Bean实例
    private Map<String, Object> objPool = Collections.synchronizedMap(new HashMap<String, Object>());
    // 保存配置文件对应的Document对象
    private Document doc;
    // 保存配置文件里的根元素
    private Element root;

    public YeekuXmlApplicationContext(String filePath) throws Exception {
        SAXReader reader = new SAXReader();
        doc = reader.read(new File(filePath));
        root = doc.getRootElement();
        initPool();
        initProp();
    }

    public Object getBean(String name) throws Exception {
        Object target = objPool.get(name);
        // 对于singleton Bean,容器已经初始化了所有Bean实例
        if (target.getClass() != String.class) {
            return target;
        } else {
            String clazz = (String) target;
            // 对于prototype并未注入属性值
            return Class.forName(clazz).newInstance();
        }
    }

    // 初始化容器中所有singleton Bean
    private void initPool() throws Exception {
        // 遍历配置文件里的每个<bean.../>元素
        for (Object obj : root.elements()) {
            Element beanEle = (Element) obj;
            // 取得<bean.../>元素的id属性
            String beanId = beanEle.attributeValue("id");
            // 取得<bean.../>元素的class属性
            String beanClazz = beanEle.attributeValue("class");
            // 取得<bean.../>元素的scope属性
            String beanScope = beanEle.attributeValue("scope");
            // 如果<bean.../>元素的scope属性不存在,或为singleton
            if (beanScope == null || beanScope.equals("singleton")) {
                // 以默认构造器创建Bean实例,并将其放入objPool中
                objPool.put(beanId, Class.forName(beanClazz).newInstance());
            } else {
                // 对于非singlton Bean,存放该Bean实现类的类名。
                objPool.put(beanId, beanClazz);
            }
        }
    }

    // 初始化容器中singleton Bean的属性
    private void initProp() throws Exception {
        // 遍历配置文件里的每个<bean.../>元素
        for (Object obj : root.elements()) {
            Element beanEle = (Element) obj;
            // 取得<bean.../>元素的id属性
            String beanId = beanEle.attributeValue("id");
            // 取得<bean.../>元素的scope属性
            String beanScope = beanEle.attributeValue("scope");
            // 如果<bean.../>元素的scope属性不存在,或为singleton
            if (beanScope == null || beanScope.equals("singleton")) {
                // 取出objPool的指定的Bean实例
                Object bean = objPool.get(beanId);
                // 遍历<bean.../>元素的每个<property.../>子元素
                for (Object prop : beanEle.elements()) {
                    Element propEle = (Element) prop;
                    // 取得<property.../>元素的name属性
                    String propName = propEle.attributeValue("name");
                    // 取得<property.../>元素的value属性
                    String propValue = propEle.attributeValue("value");
                    // 取得<property.../>元素的ref属性
                    String propRef = propEle.attributeValue("ref");
                    // 将属性名的首字母大写
                    String propNameCamelize = propName.substring(0, 1).toUpperCase()
                            + propName.substring(1, propName.length());
                    // 如果<property.../>元素的value属性值存在
                    if (propValue != null && propValue.length() > 0) {
                        // 获取设值注入所需的setter方法
                        Method setter = bean.getClass().getMethod("set" + propNameCamelize, String.class);
                        // 执行setter注入
                        setter.invoke(bean, propValue);
                    }
                    if (propRef != null && propRef.length() > 0) {
                        // 取得需要被依赖注入的Bean实例
                        Object target = objPool.get(propRef);
                        // objPool池中不存在指定Bean实例
                        if (target == null) {
                            // 此处还应处理Singleton Bean依赖prototype Bean的情形
                        }
                        // 定义设值注入所需的setter方法
                        Method setter = null;
                        // 遍历target对象所所实现的所有接口
                        for (Class superInterface : target.getClass().getInterfaces()) {
                            try {
                                // 获取设值注入所需的setter方法
                                setter = bean.getClass().getMethod("set" + propNameCamelize,
                                        superInterface);
                                // 如果成功取得该接口对应的方法,直接跳出循环
                                break;
                            } catch (NoSuchMethodException ex) {
                                // 如果没有找到对应的setter方法,继续下次循环
                                continue;
                            }
                        }
                        // 如果setter方法依然为null,
                        // 则直接取得target实现类对应的setter方法
                        if (setter == null) {
                            setter = bean.getClass().getMethod("set" + propNameCamelize,target.getClass());
                        }
                        // 执行setter注入
                        setter.invoke(bean, target);
                    }
                }
            }
        }
    }
}
3. 测试工厂类,其中Computer类、Output接口、Printer类、BetterPrinter类和上面相同

package test;

public class IoCTest {
    public static void main(String[] args) throws Exception {
        // 创建IoC容器
        ApplicationContext ctx = new YeekuXmlApplicationContext("bean.xml");
        // 从IoC容器中取出computer Bean
        Computer c = (Computer) ctx.getBean("computer");
        // 测试Computer对象
        c.keyIn("轻量级Java EE企业应用实战");
        c.keyIn("疯狂Java讲义");
        c.print();
        System.out.println(ctx.getBean("now"));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值