一文教你弄懂Java设计模式之简单工厂模式:图解+图表库代码实例

详解Java设计模式之简单工厂模式

创建型模式
  • Creational Pattern 关注对象的创建过程

  • 该模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用相分离,对用户隐藏了类的实例创建细节

  • 该模式描述如何将对象的创建与使用相分离,让用户在使用对象时无需关注对象创建过程,从而降低系统的耦合度让设计方案易于修改和扩展

  • 关注点

    • 创建什么what
    • 谁来创建who
    • 何时创建when
  • 创建模式一览

    image.png

简单工厂模式
  • 生活实例

    这张图片可以较为清晰的表达出简单工厂模式相关模式

  • 基本实现流程

    • 具体产品类:将需要创建的各种不同的产品对象的相关代码封装到具体的产品类中。可以对应到上图的苹果、香蕉、橘子
    • 抽象产品类:即将具体产品类公共的代码抽象和提取后封装在一个抽象产品类中,也就是具体产品类的父类,上图中对应水果
    • **工厂类:**提供一个工厂类用于创建各种产品,在工厂类中会提供一个创建产品的工厂方法,该方法根据所传入的参数的不同确定要创建什么具体产品
    • **客户端:**只需要调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象
定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类

  • 其他

    • 工厂类中的工厂方法(即创建实例的方法)通常都是静态方法,也被称为静态工厂方法模式
    • 需要创建什么实例,就只需要传入一个正确的参数即可,就可以获取所需要的对象,无需关注创建细节。也被称为参数化的工厂模式
模式结构
  • Factory(工厂角色)
  • Product(抽象产品角色)
  • ConcreteProduct(具体产品角色)
模式UML类图示例

image.png

模式实现(以上面水果工厂图示为例,未使用配置文件)
  • 工厂类

    package csu.edu.cn.designpattern.simplefactorypattern;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:02
     * @Theme:工厂类
     * @Description:水果工厂
     */
    public class Factory {
        public static Fruit createFruit(String type){
            if("Pear".equals(type)){
                System.out.println("正在创建---------梨");
                Pear pear = new Pear();
                pear.name = "梨";
                pear.color = "黄色";
                return pear;
            }else if("Apple".equals(type)){
                System.out.println("正在创建---------苹果");
                Apple apple = new Apple();
                apple.name = "苹果";
                apple.color = "红色";
                return apple;
            }else {
                System.out.println("正在创建---------"+type);
                System.out.println("该工厂无法创建改该产品:"+type);
                System.out.println("你去换一家工厂吧,我们实在造不出~");
                return null;
            }
        }
    }
    
    
  • 抽象产品类

    package csu.edu.cn.designpattern.simplefactorypattern;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:01
     * @Theme:抽象产品类
     * @Description:水果类
     */
    public  class Fruit {
        public String name;
        public String color;
        public void eat(){
            System.out.println("----------吃完啦----------");
        }
    }
    
  • 具体产品类

    package csu.edu.cn.designpattern.simplefactorypattern;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:02
     * @Theme:具体产品类
     * @Description:梨
     */
    public class Pear extends Fruit {
        @Override
        public void eat() {
            System.out.println(this.name+"正在被吃······");
            super.eat();
        }
    
        @Override
        public String toString() {
            return "NAME:"+this.name+"----COLOR:"+this.color;
        }
    }
    
    
    package csu.edu.cn.designpattern.simplefactorypattern;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:02
     * @Theme: 具体产品类
     * @Description: 具体产品-苹果
     */
    public class Apple extends Fruit{
        @Override
        public void eat() {
            System.out.println(this.name+"正在被吃······");
            super.eat();
        }
    
        @Override
        public String toString() {
            return "NAME:"+this.name+"----COLOR:"+this.color;
        }
    }
    
  • 客户端

    package csu.edu.cn.designpattern.simplefactorypattern;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:03
     * @Theme: 客户端
     * @Description:
     */
    public class Client {
        public static void main(String[] args) {
            //现在想让该水果工厂给我生产水果给我吃!
    
            //1.吃苹果
            Fruit fruit;
            fruit = Factory.createFruit("Apple");
            System.out.println(fruit.toString());
            fruit.eat();
    
            //1.吃梨
            fruit = Factory.createFruit("Pear");
            System.out.println(fruit.toString());
            fruit.eat();
        }
    }
    
  • 结果显示

    正在创建---------苹果
    NAME:苹果----COLOR:红色
    苹果正在被吃······
    ----------吃完啦----------
    正在创建---------梨
    NAME:梨----COLOR:黄色
    梨正在被吃······
    ----------吃完啦----------
    
实例分析

某软件公司要基于Java语言开发一套图表库,该图表库可以为应用系统提供多种不同外观的图表,例如柱状图(HistogramChart)、饼状图(PieChart)、折线图(LineChart)等。该软件公司图表库设计人员希望为应用系统开发人员提供一套灵活易用的图表库,通过设置不同的参数即可得到不同类型的图表,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。
现使用简单工厂模式来设计该图表库。

简单工厂模式实现

(1) Chart:抽象图表接口,充当抽象产品类
(2) HistogramChart:柱状图类,充当具体产品类
(3) PieChart:饼状图类,充当具体产品类
(4) LineChart:折线图类,充当具体产品类
(5) ChartFactory:图表工厂类,充当工厂类
(6) Client:客户端测试类

具体代码这里就不写了

  • 使用配置文件实现+反射实现对象的创建(改造上一次的代码)

    XMLUtil工具类实现配置文件节点读取

    package csu.edu.cn.designpattern.util;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import java.io.File;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:49
     * @Theme: XML文本节点读取
     * @Description:工具类
     */
    public class XMLUtil {
        //该方法用于从XML配置文件中提取图表类型,并返回类型名
        public static String getFruitType(){
            try {
                //创建文档对象
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = dFactory.newDocumentBuilder();
                Document doc;
                doc = builder.parse(new File("src/csu/edu/cn/designpattern/simplefactorypattern/client.xml"));
    
                //获取包含图表类型的文本结点
                NodeList nl = doc.getElementsByTagName("fruitType");
                Node classNode = nl.item(0).getFirstChild();
                String fruitType = classNode.getNodeValue().trim();
                return fruitType;
            }
            catch(Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    }
    
    
  • 配置文件内容

    <?xml version="1.0"?>
    <config>
        <fruitType>Apple</fruitType>
    </config>
    
    
  • 客户端代码改写

    package csu.edu.cn.designpattern.simplefactorypattern;
    
    import csu.edu.cn.designpattern.util.XMLUtil;
    
    /**
     * @Author: PlusHuang
     * @Date: 2021/11/28 16:03
     * @Theme: 客户端
     * @Description:
     */
    public class Client {
        public static void main(String[] args) {
            //现在想让该水果工厂给我生产水果给我吃!
    
            Fruit fruit;
            fruit = Factory.createFruit(XMLUtil.getFruitType());
            System.out.println(fruit.toString());
            fruit.eat();
    
        }
    }
    
    
    运行结果
    正在创建---------苹果
    NAME:苹果----COLOR:红色
    苹果正在被吃······
    ----------吃完啦----------
    
回顾Java创建对象的集中方法
  • new关键字
  • 反射机制
  • 克隆方法
  • 工厂类
对象的创建与使用分离的其他好处
  • 防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中,解决代码重复、创建蔓延的问题

  • 构造函数的名字都与类名相同,从构造函数和参数列表中大家很难了解不同构造函数所构造的产品的差异,将对象的创建过程封装在工厂类中,可以提供一系列名字完全不同的工厂方法,每一个工厂方法对应一个构造函数,客户端可以以一种更加可读、易懂的方式来创建对象

什么时候不需要工厂

无须为系统中的每一个类都配备一个工厂类
如果一个类很简单,而且不存在太多变化,其构造过程也很简单,此时就无须为其提供工厂类,直接在使用之前实例化即可
导致工厂泛滥,增加系统的复杂度
例如:java.lang.String

简单工厂模式的简化

将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中

模式优点
  • 实现了对象创建和使用的分离
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性
模式缺点
  • 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
  • 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度
  • 系统扩展困难,一旦添加新产品不得不修改工厂逻辑
  • 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展
模式适用环境
  • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
  • 客户端只知道传入工厂类的参数,对于如何创建对象并不关心扩展
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
责任链设计模式是一种行为型设计模式,用于将请求的发送者和接收者解耦,使多个对象都有机会处理该请求。该模式将这些对象串成链,并沿着这条链传递请求,直到有一个对象能够处理它为止。 责任链模式的核心是定义一个处理请求的抽象类或接口,然后让多个具体的处理者对象继承或实现这个类/接口。每个具体的处理者对象都包含一个对下一个处理者对象的引用,形成一个链式结构。 当一个请求进入责任链时,责任链中的每个处理者都有机会处理该请求。如果可以处理请求,则进行处理;如果不能处理,则将请求传递给下一个处理者,直到有一个处理者能够处理它。 责任链模式的关键点是要找到合适的处理者顺序和条件。通常情况下,责任链模式适用于以下情况: 1. 有多个对象可以处理同一类型的请求,但具体由哪个对象来处理由运行时决定。 2. 不明确请求的接收者,希望请求在一个对象链中流动,直到被处理。 3. 需要动态地指定可以处理请求的对象集合。 使用责任链模式可以实现请求发送者和接收者的解耦,增加代码的灵活性和可扩展性。但同时也需要注意责任链的长度和效率问题,避免责任链过长或造成性能问题。 总结一下,责任链设计模式是一种将请求发送者和接收者解耦的设计模式,通过将多个处理者对象串成链,沿着这条链传递请求,直到有一个处理者能够处理它。这样可以增加代码的灵活性和可扩展性,适用于有多个对象可以处理同一类型请求的情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值