设计模式学习:工厂模式

概念

工厂模式用于方便快捷地创建对象,而不用关心这个对象是如何创建的

工厂模式使用一个工厂方法代替new关键字来实例化对象

工厂模式分简单工厂模式、工厂方法模式和抽象工厂模式

简单工厂模式是工厂方法模式的一个特例,抽象工厂模式是工厂方法模式的扩展

工厂(Factory)定义一个接口来创建对象,但是让子类来决定哪些对象需要被实例化

工厂方法模式类图:


抽象工厂模式类图:


作用

降低了对象类和使用类的耦合性,当对象类发生变化时,使用类并不需要作出过多的修改

比如一个对象的构造方法要求传入多个参数,当我们使用new来构造实例时就要把所有参数传进去,而一旦这个类的构造方法所需参数发生了改变,我们就必须在每一个使用new的语句中同步修改,这无疑是十分繁琐且容易出错的。如果使用工厂模式,我们仅需修改create方法这一个位置就可以了


使用场景

有一组类似但不是同一个类的对象需要创建

在编码时不能预见需要创建哪种类的实例(动态创建)


例子

我们日常生活中可能会用到很多不同颜色的笔,比如写一篇笔记的时候,使用黑笔写内容,使用蓝笔写注释,使用红笔来突出重点,而记笔记的纸也可以有很多种,比如白纸、单线纸、双线纸等等,如果用代码表示的话,就需要new很多个不同的类的实例对象,这样做是不方便也不利于维护的。那么我们就可以使用工厂模式来为这些笔和纸构建实例对象。

不同的笔其功能都是一样的,都是用来写字,我们就可以创建一个笔的接口,并声明一个写字的方法,所有笔的类都要实现这个接口,在Factory类的Create方法种返回这个接口的对象,就是一个具体的笔的实例了


代码示例

//笔的接口
public interface IPen {
    void writeText();
}
//笔的工厂类
public class PenFactory {
    public static final int RED_PEN = 0;
    public static final int BLACK_PEN = 1;
    public static final int BLUE_PEN = 2;

    /**
     * 使用反射机制来加载产品类
     *
     * @param key
     * @return
     */
    static IPen Create(String key) {
        PropertiesReader reader = new PropertiesReader();
        Map<String, String> map = reader.getProperties();
        String className = map.get(key);
        if (className == null) {
            throw new NullPointerException("没有相应的类,key:" + key);
        }
        try {
            return (IPen) Class.forName(className).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用颜色代码判断要生产什么笔
     *
     * @param colorCode
     * @return
     */
    static IPen Create(int colorCode) {
        switch (colorCode) {
            case RED_PEN:
                return new RedPen();
            case BLACK_PEN:
                return new BlackPen();
            case BLUE_PEN:
                return new BluePen();
            default:
                throw new NullPointerException("没有颜色值为" + colorCode + "的笔");
        }
    }
}

上面的代码中有两种Create方法,一种是使用int类型作为笔的代码,这种写法较为简单,但是当我们的产品类有很多时,使用这种方法就要声明同样多的int值,这样就变得很不方便了,因此我们可以使用另一种类加载的方式。

类加载是使用Java反射机制实现的,通过Class类的forName方法找出一个类,并使用newInstance方法创建一个实例。

在forName(String className)中要传入完整的类名(包名+类名称),这里是使用了一个映射(propertites文件),用指定字符串映射了相应的完整类名。


//黑笔,其他笔也是一样的写法
public class BlackPen implements IPen {
    @Override
    public void writeText() {
        System.out.println("使用黑笔写字");
    }
}
//测试类
public class Test {

    public static void main(String[] args) {
        //使用映射
        IPen redPen = PenFactory.Create("red");
        redPen.writeText();
        IPen bluePen = PenFactory.Create("blue");
        bluePen.writeText();
        //使用笔的代码
        IPen blackPen = PenFactory.Create(PenFactory.BLACK_PEN);
        blackPen.writeText();
        IPen none = PenFactory.Create(3);
        none.writeText();
    }
}

运行结果:



猜你喜欢

转载自blog.csdn.net/lllx9464/article/details/80490912
今日推荐