设计模式之简单工厂模式

258 阅读4分钟

简单工厂模式

Simple Factory Pattern,是指一个工厂对象决定创建出哪一种产品类的实例,属于创建型模式。

适用场景

1、工厂类负责创建的对象较少。

2、客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。

优点

只需要传入一个正确的参数,就可以获取你所需要的对象,无需知道其创建细节。

缺点

1、工厂类的职责相对过重,增加新的产品时需要修改工厂类的判断逻辑违背开闭原则。

2、不易于扩展过于复杂的产品结构。

反例

每一个课程都要自己new,会产生很多冗余代码,没有面向抽象编程。

类图

image.png

package pattern.factory.simplefactory;
public class Test {
    public static void main(String[] args) {
        Couse couse = new Couse();
        couse.record();;
        JavaCouse javaCouse = new JavaCouse();
        javaCouse.record();
    }
}
package pattern.factory.simplefactory;
/**
 *  课程
 */
public class Couse {
    public void record() {
        System.out.println("录制Python课程");
    }
}
package pattern.factory.simplefactory;
/**
 *  录制Java课程
 */
public class JavaCouse {
    public void record() {
        System.out.println("录制Java课程");
    }
}

正例

反例有一个共性,都叫课程couse。

先从总体出发,先不考虑细节,先把课程抽象出来一个接口。

架构师思维,预先考虑好未来可能会发生的改变。

工厂:把创建对象的过程包装起来,具体的创建用户不用关心,用户只需要关心需要创建什么。

image.png

package pattern.factory.simplefactory;
public class Test {
    public static void main(String[] args) {
        new CouseFactory().create("Java").record();
    }
}
package pattern.factory.simplefactory;
/**
 *  课程
 */
public interface ICouse {
    void record();
}

package pattern.factory.simplefactory;
/**
 *  录制Java课程
 */
public class JavaCouse implements ICouse{
    @Override
    public void record() {
        System.out.println("录制Java课程");
    }
}
package pattern.factory.simplefactory;
/**
 * 录制Python课程
 */
public class PythonCouse implements ICouse {
    @Override
    public void record() {
        System.out.println("Python课程");
    }
}
package pattern.factory.simplefactory;
/**
 *  课程工厂
 */
public class CouseFactory {
    public ICouse create(String name) {
        if("java".equals(name)) {
            return new JavaCouse();
        }else if("python".equals(name)){
            return new PythonCouse();
        }
        return null;
    }
}

优点:

经过上面的改造,用户只跟工厂打交道,只在CouseFactory.create(String name)方法中传入一个字符串,就可以得到自己想要的对象。这是工厂模式的思想。

缺点:

1、CouseFactory.create(String name) 方法体根据传入的name进行if else判断每次增加课程Couse都需更改此工厂方法,以适配新的课程Couse,容易出错。不符合开闭原则。

2、CouseFactory.create(String name) 入参字符串用户容易传错,没有章法,显然这不是很好的方式。

运用Java反射技术升级1

image.png

改造CouseFactory工厂类,传入全类名pattern.factory.simplefactory.JavaCouse

package pattern.factory.simplefactory;
public class Test {
    public static void main(String[] args) {
        new CouseFactory().create("pattern.factory.simplefactory.JavaCouse").record();
    }
}
package pattern.factory.simplefactory;
/**
 *  课程工厂
 */
public class CouseFactory {
    public ICouse create(String className) {
        try {
            if(null != className || "".equals(className)) {
                return (ICouse) Class.forName(className).newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

优点:

1、经过上面的改造,用户只跟工厂打交道,只在CouseFactory.create(String className)方法中传入一个字符串,就可以得到自己想要的对象。这是工厂模式的思想。

2、CouseFactory.create(String className) 每次增加课程Couse都不需更改此工厂方法,用户只需要输入正确的全类名,就可以适配新的课程Couse。对于此产品而言符合开闭原则。

缺点:

1、CouseFactory.create(String className) 入参全类名用户容易传错,显然这不是很好的方式。

运用Java反射技术升级2

image.png

package pattern.factory.simplefactory;
public class Test {
    public static void main(String[] args) {
        new CouseFactory().create(JavaCouse.class).record();
    }
}
package pattern.factory.simplefactory;
/**
 *  课程工厂
 */
public class CouseFactory {
    public ICouse create(Class clazz) {
        try {
            if(clazz != null) {
                return (ICouse) clazz.newInstance();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

优点:

1、经过上面的改造,用户只跟工厂打交道,只在CouseFactory.create(String className)方法中传入一个字符串,就可以得到自己想要的对象。这是工厂模式的思想。

2、CouseFactory.create(String className) 每次增加课程Couse都不需更改此工厂方法,用户只需要输入正确的全类名,就可以适配新的课程Couse。对于此产品而言符合开闭原则。

3、CouseFactory.create(String className) 入参是Class用户不会传错。

缺点:

1、CouseFactory.create(Class clazz) 入参是Class用户不会传错了,但是可能会出现另外一个问题return (ICouse) clazz.newInstance();如果对类没有约束,这里强转成ICouse就会发生异常。

运用Java反射技术升级3

image.png

package pattern.factory.simplefactory;
/**
 *  课程工厂
 */
public class CouseFactory {
    public ICouse create(Class<? extends ICouse> clazz) {
        try {
            if(clazz != null) {
                return clazz.newInstance();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

优点:

用户只需要跟工厂打交道,CouseFactory.create(Class<? extends ICouse> clazz)方法中,用户只需且只能传入产品ICouse的子类符合单一职责原则,增加新的课程Couse不需要改变工厂方法,对于此产品而言符合开闭原则。

其他例子

1、Jdk中例子: Calendar.getInstance();

2、Log4j中的例子: LoggerFactory.getLogger();