手把手教你学会使用设计模式之工厂模式

命运对每个人都是一样的,不一样的是各自的努力和付出不同,付出的越多,努力的越多,得到的回报也越多,在你累的时候请看一下身边比你成功却还比你更努力的人,这样,你就会更有动力。

导读:本篇文章讲解 手把手教你学会使用设计模式之工厂模式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

设计模式之工厂模式

简介

工厂模式称为工厂方法模式,是一种创建型设计模式,其在父类提供一个创建对象的方法,允许子类决定实例化对象的类型。

工厂模式是java中最常见的模式,本意是为了提高代码结构的拓展性,让外部更简单的调用。也是去掉if-else的一种解决方式,缺点是需要实现的类比较多。

工厂模式分为3种:工厂方法模式、简单/静态工厂模式、抽象工厂模式。

核心:将对象的创建和使用做分离。

未用设计模式实例

需求1

有一个花为电子厂,可以生产鼠标,假设我们通过按钮来点击触发生产。

在这里插入图片描述

代码如下:

/**
 * 花为电子厂,生产鼠标
 */
public void huaweiFactory() {
    System.out.println("生产鼠标");
}

调用方

public static void main(String[] args) {
    new Controller().huaweiFactory();
}

需求2

随着公司不断扩大,业务也更加广泛,该家电子厂也可以生产键盘。

在这里插入图片描述

我们一般会增加一个类型来区分。

代码如下:

/**
 * 花为电子厂,可以生产鼠标和键盘
 * @param type 1鼠标。2键盘
 */
public void huaweiFactory(Integer type) {
    if (type == 1) {
        System.out.println("生产鼠标");
    } else if (type == 2) {
        System.out.println("生产键盘");
    }
}

调用方

public static void main(String[] args) {
    //生产鼠标
    new Controller().huaweiFactory(1);
    //生产键盘
    new Controller().huaweiFactory(2);
}

需求3

业务又增加,该家电子厂可以生产耳机、数据线、充电宝。

在这里插入图片描述

代码如下:

/**
 * 花为电子厂
 * @param type 1鼠标、2键盘、3耳机、4数据线、5充电宝
 */
public void huaweiFactoryNew(Integer type) {
    if (type == 1) {
        System.out.println("生产鼠标");
    } else if (type == 2) {
        System.out.println("生产键盘");
    } else if (type == 3) {
        System.out.println("生产耳机");
    } else if (type == 4) {
        System.out.println("生产数据线");
    } else if (type == 5) {
        System.out.println("生产充电宝");
    }
}

调用方

public static void main(String[] args) {
    new Controller().huaweiFactoryNew(1);
    new Controller().huaweiFactoryNew(2);
    new Controller().huaweiFactoryNew(3);
    new Controller().huaweiFactoryNew(4);
    new Controller().huaweiFactoryNew(5);
}

小结

果然没有什么需求是 if-else 解决不了的,如果有,那就多写几个。但是也存在诸多问题:

  1. 实际代码逻辑肯定不是一行,可能几十行上百行,参数也不会是一个,也可能会根据类型增加不同的参数。当增加新的生产线后整个类会变得冗长,阅读难度增加,因为逻辑的不同也会导致难以维护。
  2. 该类职责过重,违反了单一职责
  3. 当增加新的生产时,需要修改原代码,调用方也需要修改,违反了开闭原则

这时,我们可以用工厂模式来进行优化。

简单/静态工厂模式

简介

简单/静态工厂模式一般我们叫简单工厂模式,由工厂对象决定创建哪个实例

对于需求2和需求3我们可以进行改进。

概览图

在这里插入图片描述

代码结构

在这里插入图片描述

代码

创建一个生产方法,子类可以生产鼠标、键盘等。

public interface ProductionService {
    /**
     * 生产
     */
    void production();
}

生产鼠标

public class MouseServiceImpl implements ProductionService {
    @Override
    public void production() {
        System.out.println("生产鼠标");
    }
}

生产键盘

public class KeyboardServiceImpl implements ProductionService {
    @Override
    public void production() {
        System.out.println("生产键盘");
    }
}

创建生产工厂,决定生产什么。

public class ProductionFactory {
    public ProductionService product(Integer type) {
        if (type == 1) {
            return new MouseServiceImpl();
        } else if (type == 2) {
            return new KeyboardServiceImpl();
        }
        return null;
    }
}

调用方

public class Controller {
    public static void main(String[] args) {
        new ProductionFactory().product(1).production();
        new ProductionFactory().product(2).production();
    }
}

新增需求

当需要增加需求3中的耳机时

流程图如下:

在这里插入图片描述

我们创建一个生产耳机的子类。

public class HeadsetServiceImpl implements ProductionService {
    @Override
    public void production() {
        System.out.println("生产耳机");
    }
}

在生产工厂增加类型3

public class ProductionFactory {
    public ProductionService product(Integer type) {
        if (type == 1) {
            return new MouseServiceImpl();
        } else if (type == 2) {
            return new KeyboardServiceImpl();
        } else if (type == 3) {
            return new HeadsetServiceImpl();
        }
        return null;
    }
}

调用方增加类型3即可。

public class Controller {
    public static void main(String[] args) {
        new ProductionFactory().product(1).production();
        new ProductionFactory().product(2).production();
        new ProductionFactory().product(3).production();
    }
}

小结

  1. 当增加新的生产线,只需要增加生产子类,修改工厂类,结构清晰。
  2. 只有一个具体工厂来创建对象,代码量较少。
  3. 不符合开闭原则,因为需要修改工厂类。

工厂方法模式

简介

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,仅负责具体工厂子类必须实现的接口,将创建的工作交给子类。这样的好处是可以使在不修改具体工厂角色的情况下进行拓展

工厂方法模式是简单工厂模式的衍生、实现开闭原则可拓展。

工厂方法模式有四要素:

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  2. 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

概览图

在这里插入图片描述

代码结构

在这里插入图片描述

代码

创建抽象产品类

public interface IProduction {
    /**
     * 生产接口
     */
    void production();
}

具体产品1:鼠标

public class MouseService implements IProduction {
    @Override
    public void production() {
        System.out.println("生产鼠标");
    }
}

具体产品2:键盘

public class KeyboardService implements IProduction {
    @Override
    public void production() {
        System.out.println("生产键盘");
    }
}

创建抽象工厂类

public interface IFactory {
    /**
     * 生产
     * @return
     */
    IProduction prod();
}

具体工厂1:鼠标

public class MouseFactory implements IFactory {
    @Override
    public IProduction prod() {
        return new MouseService();
    }
}

具体工厂2:键盘

public class KeyboardFactory implements IFactory {
    @Override
    public IProduction prod() {
        return new KeyboardService();
    }
}

调用方

public class Controller {
    public static void main(String[] args) {
        //鼠标
        IFactory mouseFactory = new MouseFactory();
        mouseFactory.prod().production();
        //键盘
        IFactory keyboardFactory = new KeyboardFactory();
        keyboardFactory.prod().production();
    }
}

新增需求

如果需要新增生产耳机。

在这里插入图片描述

则增加具体产品耳机和具体工厂耳机即可。

小结

  1. 明确了各个类的职责,结构清晰。
  2. 有新的产品增加,只需要增加具体产品和具体工厂即可。不会影响之前的代码,容易维护。
  3. 需要编写工厂代码,增加了工作量。类的数量增加,复杂度也会增加。

抽象工厂模式

简介

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品

和工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等4个要素组成,但是略有不同。

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
  2. 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

实例

花为电子厂生产鼠标和键盘,公司发展越来越强大,收购了一家电子厂叫大米电子厂。这个电子厂也生产鼠标和键盘,总公司决定兼容一起生产。

第一个结论说过,没有什么需求是 if-else 解决不了的,如果有,那就多写几个。

代码如下:

/**
 * 花为和大米电子厂生产
 * @param num  1花为,2大米
 * @param type 1鼠标,2键盘
 */
public void huaweiAndDami(Integer num, Integer type) {
    if (num == 1) {
        if (type == 1) {
            System.out.println("花为电子厂,生产鼠标");
        } else if (type == 2) {
            System.out.println("花为电子厂,生产键盘");
        }
    } else if (num == 2) {
        if (type == 1) {
            System.out.println("大米电子厂,生产鼠标");
        } else if (type == 2) {
            System.out.println("大米电子厂,生产键盘");
        }
    }
}

调用方:

public static void main(String[] args) {
    new Controller().huaweiAndDami(1, 1);
    new Controller().huaweiAndDami(1, 2);
    new Controller().huaweiAndDami(2, 1);
    new Controller().huaweiAndDami(2, 2);
}

nice,只要 if-else 写的6,就没有实现不了的需求,实现不了就是 if-else 写的不够多。

针对上面的需求,我们就可以使用抽象工厂模式来优化。

概览图

在这里插入图片描述

代码结构

在这里插入图片描述

代码

大米相关

创建抽象产品类-大米

public interface IDami {
    void production();
}

创建具体产品类-鼠标

public class DMouseService implements IDami {
    @Override
    public void production() {
        System.out.println("大米电子厂,生产鼠标");
    }
}

创建具体产品类-键盘

public class DKeyboardService implements IDami {
    @Override
    public void production() {
        System.out.println("大米电子厂,生产键盘");
    }
}

创建抽象工厂类

public interface IDFactory {
    /**
     * 生产鼠标
     * @return
     */
    IDami mouse();

    /**
     * 生产键盘
     * @return
     */
    IDami keyboard();
}

创建具体工厂类

public class DFactoryService implements IDFactory {
    @Override
    public IDami mouse() {
        return new DMouseService();
    }

    @Override
    public IDami keyboard() {
        return new DKeyboardService();
    }
}
花为相关

创建抽象产品类-花为

public interface IHuawei {
    void production();
}

创建具体产品类-鼠标

public class HMouseService implements IHuawei {
    @Override
    public void production() {
        System.out.println("花为电子厂,生产鼠标");
    }
}

创建具体产品类-键盘

public class HKeyboardService implements IHuawei {
    @Override
    public void production() {
        System.out.println("花为电子厂,生产键盘");
    }
}

创建抽象工厂类

public interface IHFactory {
    /**
     * 生产鼠标
     * @return
     */
    IHuawei mouse();

    /**
     * 生产键盘
     * @return
     */
    IHuawei keyboard();
}

创建具体工厂类

public class HFactoryService implements IHFactory {
    @Override
    public IHuawei mouse() {
        return new HMouseService();
    }

    @Override
    public IHuawei keyboard() {
        return new HKeyboardService();
    }
}
调用方
public class Controller {
    public static void main(String[] args) {
        //花为电子厂
        IHFactory ihFactory = new HFactoryService();
        ihFactory.mouse().production();
        ihFactory.keyboard().production();
        //大米电子厂
        IDFactory idFactory = new DFactoryService();
        idFactory.mouse().production();
        idFactory.keyboard().production();

        //输出结果
//        花为电子厂,生产鼠标
//        花为电子厂,生产键盘
//        大米电子厂,生产鼠标
//        大米电子厂,生产键盘
    }
}

新增需求

如果或许又开了一家子工厂桔子,也生产鼠标键盘。

则如下图拓展即可。

在这里插入图片描述

不会影响之前的业务。

小结

  1. 当新增一个电子厂时,不需要修改原有代码,满足开闭原则。如增加桔子工厂。
  2. 当增加一个具体产品时,则所有的工厂类都需要进行修改,不满足开闭原则。如增加生产耳机。
  3. 当系统中只有一个电子厂时,抽象工厂模式就是工厂方法模式。

总结

  1. 简单工厂模式:由工厂对象决定创建哪个实例,实现简单,但是需要频繁修改工厂类,可能会引发新的bug,不符合开闭原则。
  2. 工厂方法模式:是简单工厂模式的拓展,结构清晰,拓展功能就是拓展工厂,不需要修改工厂类,但是增加了工作量。
  3. 抽象工厂模式:是工厂方法模式的拓展,在特定条件下才符合开闭原则。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/143360.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!