设计模式(二):简单工厂

简单工厂属于创建型模式,但不在GoF23种设计模式行列中,具体参考上篇博文设计模式(一):开篇中的模式分类,但他确是我们学习计算机编程最早接触的一种模式,也是我们在不知不觉中使用的模式。

1.基本定义

由工厂对象决定创建出哪一种类型的产品实例。看到这句话可能有点懵,说白了就是我提供一个接口,你传一个类型参数给我,我返给你一个对应的实例。

1.1优点

只需要传递正确的参数,就可以获取到产品实例,不关心具体的创建过程细节。

1.2缺点

工厂类职责实现过重,增加新的类型时,需要修改工厂类。违法开闭原则(对扩展开发,对修改关闭)。从而对既有功能模块带来修改风险。

2.coding

下面我们以车辆生产作为背景介绍简单工厂模式,虚拟的情况不用对号入座。工厂有若干个生产线,可以生产各种汽车,比如奔驰、别克、法拉利等等。根据订单情况,选择生产。代码如下:

2.1 v0.1版

抽象类生产线

package com.xxfamly.creational.simpleFactory;

/**
 * 生产线抽象类
 */
public abstract class Pipeline {
    public abstract void produce();
}

奔驰生产线继承抽象类

package com.xxfamly.creational.simpleFactory;

/**
 * 奔驰生产线
 */
public class BenzPipeline extends Pipeline {
    @Override
    public void produce() {
        System.out.println("生产奔驰汽车");
    }
}

别克生产线继承抽象类

package com.xxfamly.creational.simpleFactory;

/**
 * 别克生产线
 */
public class BuickPipeline extends Pipeline {
    @Override
    public void produce() {
        System.out.println("生产别克汽车");
    }
}

法拉利生产线继承抽象类

package com.xxfamly.creational.simpleFactory;

/**
 * 法拉利生产线
 */
public class FerrariPipeline extends Pipeline {
    @Override
    public void produce() {
        System.out.println("生产法拉利汽车");
    }
}

 客户端指定生产车型,我们这个系列的博文统一使用Client.java作为客户端例子。

package com.xxfamly.creational.simpleFactory;

/**
 * 模拟客户端
 */
public class Client {

    public static void main(String[] args) {
        //生产法拉利
        Pipeline p1 = new FerrariPipeline();
        p1.produce();

        //生产奔驰
        Pipeline p2 = new BenzPipeline();
        p2.produce();

        //生产别克
        Pipeline p3 = new BuickPipeline();
        p3.produce();
    }
}

运行结果

com.xxfamly.creational.simpleFactory.Client
生产法拉利汽车
生产奔驰汽车
生产别克汽车

Process finished with exit code 0

可以看到程序根据客户端的指令生产了3种汽车。

我们来看一下UML类图

可以看到客户端同时依赖所有的生产线,如果任何生产线发生变动都会引发客户端的调整,客户端过多的关注生产细节,不利于系统扩展和集中维护。

2.2 v0.2版

我们来调整一下,增加一个工厂类,负责生产细节。

package com.xxfamly.creational.simpleFactory;

/**
 * 生产线工厂类
 * 
 * 根据传入类型返回具体的产品实例
 */
public class PipelineFactory {
    public Pipeline getPiteline(String type){

        if("benz".equalsIgnoreCase(type)){
            return new BenzPipeline();
        }else if("buick".equalsIgnoreCase(type)){
            return new BuickPipeline();
        }else if("ferrari".equalsIgnoreCase(type)){
            return new FerrariPipeline();
        }else{
            return null;
        }
    }
}

调整一下客户端代码

package com.xxfamly.creational.simpleFactory;

/**
 * 模拟客户端
 */
public class Client {

    public static void main(String[] args) {
       /* //生产法拉利
        Pipeline p1 = new FerrariPipeline();
        p1.produce();

        //生产奔驰
        Pipeline p2 = new BenzPipeline();
        p2.produce();

        //生产别克
        Pipeline p3 = new BuickPipeline();
        p3.produce();*/

        //简单工厂模式,违反开闭原则
        PipelineFactory pipelineFactory = new PipelineFactory();
        Pipeline p1 = pipelineFactory.getPiteline("benz");
        if (p1 == null) return;
        p1.produce();

        Pipeline p2 = pipelineFactory.getPiteline("buick");
        if (p2 == null) return;
        p2.produce();

        Pipeline p3 = pipelineFactory.getPiteline("ferrari");
        if (p3 == null) return;
        p3.produce();
    }
}

运行结果与v0.1版本一致。

查看UML类图

从类图中,客户端只依赖工厂类,生产的细节隐藏起来了,解放客户端编程的代码量。同时便于系统扩展和集中维护。但是我们也从中能看到工厂的职责是非常繁重的,且违反开闭原则这点我们前文提到了。

2.3 V0.3版

我们利用Java的反射机制,改进工厂类,使之能够符合开闭原则,如下。

简单工厂进阶类

package com.xxfamly.creational.simpleFactory;

/**
 * 简单工厂进阶类
 */
public class PipeFactoryAdvance {
    public Pipeline getPiteline(Class clazz){

        try {
            return (Pipeline)clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return null;
    }
}

 客户端类改造

package com.xxfamly.creational.simpleFactory;

/**
 * 模拟客户端
 */
public class Client {

    public static void main(String[] args) {
       /* //生产法拉利
        Pipeline p1 = new FerrariPipeline();
        p1.produce();

        //生产奔驰
        Pipeline p2 = new BenzPipeline();
        p2.produce();

        //生产别克
        Pipeline p3 = new BuickPipeline();
        p3.produce();*/

        /*//简单工厂模式,违反开闭原则
        PipelineFactory pipelineFactory = new PipelineFactory();
        Pipeline p1 = pipelineFactory.getPiteline("benz");
        if (p1 == null) return;
        p1.produce();

        Pipeline p2 = pipelineFactory.getPiteline("buick");
        if (p2 == null) return;
        p2.produce();

        Pipeline p3 = pipelineFactory.getPiteline("ferrari");
        if (p3 == null) return;
        p3.produce();*/

        //简单工厂进阶,对修改关闭,对扩展放开
        PipeFactoryAdvance p = new PipeFactoryAdvance();
        Pipeline p1 = null;
        p1 = p.getPiteline(BenzPipeline.class);
        if(p1 == null) return;
        p1.produce();

        p1 = p.getPiteline(BuickPipeline.class);
        if(p1 == null) return;
        p1.produce();

        p1 = p.getPiteline(FerrariPipeline.class);
        if(p1 == null) return;
        p1.produce();
    }
}

 运行结果

生产奔驰汽车
生产别克汽车
生产法拉利汽车

Process finished with exit code 0

运行结果与V0.1,V0.2一致,看UML类图

从类图中可以看出,此时工厂类不依赖具体的生产线,再扩展一个生产线也不要调整工厂类,符合开闭原则,反射反射程序员最爱。

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值