常用设计模式之工厂

一、工厂设计模式概念

工厂模式(Factory Pattern)很简单,就是用来创建对象实例的,所有的对象实例,都交给工厂类生成。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则,如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦,在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

 二、类型

本篇主要介绍三种工厂设计模式的使用:简单工厂、工厂方法、抽象工厂

  • 简单工厂(Simple Factory)

简单工厂实际不能算作一种设计模式,它引入了创建者的概念,将实例化的代码从应用代码中抽离,在创建者类的静态方法中只处理创建对象的细节,后续创建的实例如需改变,只需改造创建者类即可,但由于使用静态方法来获取对象,使其不能在运行期间通过不同方式去动态改变创建行为,因此存在一定局限性。

定义:一个工厂方法,依据传入的参数,生成对应的产品对象;

优点:

  1. 客户与具体实现类松耦合,对于客户来说,他只需要传入对象的类型参数,就可以通过工厂获得所需要的对象实例
  2. 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:

  1. 与具体实现类松耦合,却又和工厂绑在了一起,负担太重。当所要生产产品种类非常多时,工厂方法的代码量会很庞大。
  2. 对于增加新的产品,需要修改工厂方法代码来实现。

角色:

  1. 抽象产品
  2. 具体产品
  3. 具体工厂
  4. 产品使用者

使用说明:先将产品类抽象出来,比如,苹果和梨都属于水果,抽象出来一个水果类Fruit,苹果和梨就是具体的产品类,然后创建一个水果工厂,分别用来创建苹果和梨;代码如下:

/**
     * 抽象产品-水果接口
     */
    public interface Fruit {
        String getCategory();
    }

    /**
     * 具体实现类-苹果
     */
    public static class Apple implements Fruit {
        @Override
        public String getCategory() {
            return "apple";
        }
    }

    /**
     * 具体实现类-梨
     */
    public static class Pear implements Fruit {
        @Override
        public String getCategory() {
            return "pear";
        }
    }

    /**
     * 具体工厂-水果工厂类
     */
    public static class FruitFactory {
        Fruit createFruit(String type) {
            Fruit fruit;
            switch (type) {
                case "apple":
                    fruit = new Apple();
                    break;
                case "pear":
                    fruit = new Pear();
                    break;
                default:
                    fruit = new Apple();
                    break;
            }
            return fruit;
        }
    }

    public static void main(String[] args) {
        //产品使用者
        FruitFactory mFactory = new FruitFactory();
        System.out.println(mFactory.createFruit("apple").getCategory());
        System.out.println(mFactory.createFruit("pear").getCategory());
    }

以上的这种方式,每当添加一种水果,就必然要修改工厂类,这显然违反了开闭原则(对拓展开放,对修改关闭),亦不可取;所以简单工厂只适合于产品对象较少,且产品固定的需求,对于产品变化无常的需求来说显然不合适。

  • 工厂方法(Factory Method)

工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。

优点:

  1. 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1)
  2. 同时增加某一类”东西“并不需要修改工厂类,只需要添加生产这类”东西“的工厂即可,使得工厂类符合开放-封闭原则。

缺点:

  1. 相比简单工厂,实现略复杂。
  2. 对于某些可以形成产品族的情况处理比较复杂(可以用抽象工厂来实现)。

定义:将工厂提取成一个接口或抽象类,具体生产什么产品由子类决定;
角色:

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

使用说明:和上例中一样,产品类抽象出来,这次我们把工厂类也抽象出来,生产什么样的产品由子类来决定;
代码如下:水果接口 苹果类和梨类 代码和上例一样

  /**
     * 抽象工厂类-工厂接口
     */
    public interface FruitFactory {
        Fruit createFruit();//生产水果
    }

    /**
     * 具体工厂类-苹果工厂
     */
    public static class AppleFactory implements FruitFactory {
        @Override
        public Fruit createFruit() {
            return new Apple();
        }
    }

    /**
     * 具体工厂类-梨工厂
     */
    public static class PearFactory implements FruitFactory {
        @Override
        public Fruit createFruit() {
            return new Pear();
        }
    }

    public static void main(String[] args) {
        //具体使用
        AppleFactory appleFactory = new AppleFactory();
        PearFactory pearFactory = new PearFactory();
        Apple apple = (Apple) appleFactory.createFruit();//获得苹果
        Pear pear = (Pear) pearFactory.createFruit();//获得梨
        System.out.println(apple.create());
        System.out.println(pear.create());
    }

以上这种方式,当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同(即接口)来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并继承抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的,虽然解耦了,但是问题根本还是没有解决,换汤没换药,如果需要的产品很多的话,需要创建非常多的工厂,所以这种方式的缺点也很明显。

  • 抽象工厂(Abstract Factory)

 抽象工厂是应对产品族概念的。围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

定义:为创建一组相关或者是相互依赖的对象提供的一个接口,而不需要指定它们的具体类。
角色:和工厂方法一样
抽象工厂和工厂方法的模式基本一样,区别在于,工厂方法是生产一个具体的产品,而抽象工厂可以用来生产一组相同,有相对关系的产品;重点在于一组,一批,一系列;举个例子,假如生产小米手机,小米手机有很多系列,小米note、红米note等;假如小米note生产需要的配件有825的处理器,6英寸屏幕,而红米只需要650的处理器和5寸的屏幕就可以了;用抽象工厂来实现:

    /**
     * cpu接口和实现类
     */
    public interface Cpu {
        String create();

        class Cpu650 implements Cpu {
            @Override
            public String create() {
                return "CPU-650";
            }
        }

        class Cpu825 implements Cpu {
            @Override
            public String create() {
                return "CPU-825";
            }
        }
    }

    /**
     * 屏幕接口和实现类
     */
    public interface Screen {

        String create();

        class Screen5 implements Screen {

            @Override
            public String create() {
                return "ScreenSize-5";
            }
        }

        class Screen6 implements Screen {

            @Override
            public String create() {
                return "ScreenSize-6";
            }
        }
    }

    /**
     * 工厂接口
     */
    public interface PhoneFactory {

        Cpu getCpu();//使用的cpu

        Screen getScreen();//使用的屏幕
    }

    /**
     * 具体工厂实现类:小米手机工厂
     */
    public static class XiaoMiFactory implements PhoneFactory {
        @Override
        public Cpu getCpu() {
            return new Cpu.Cpu825();//高性能处理器
        }

        @Override
        public Screen getScreen() {
            return new Screen.Screen6();//6寸大屏
        }
    }

    /**
     * 具体工厂实现类:红米手机工厂
     */
    public static class HongMiFactory implements PhoneFactory {

        @Override
        public Cpu getCpu() {
            return new Cpu.Cpu650();//高效处理器
        }

        @Override
        public Screen getScreen() {
            return new Screen.Screen5();//小屏手机
        }
    }

    public static void main(String[] args) {
        PhoneFactory hongMiFactory = new HongMiFactory();
        PhoneFactory xiaoMiFactory = new XiaoMiFactory();
        System.out.println(hongMiFactory.getCpu().create()+"+" +hongMiFactory.getScreen().create());
        System.out.println(xiaoMiFactory.getCpu().create()+"+" +xiaoMiFactory.getScreen().create());
    }

以上例子可以看出,抽象工厂可以解决一系列的产品生产的需求,对于大批量,多系列的产品,用抽象工厂可以更好的管理和扩展;

三、区别

  1. 简单工厂 : 用来生产同一等级结构中的任意产品,可以将客户程序从具体类解耦。(不支持拓展增加产品)
  2. 工厂方法 :使用继承,把对象的创建委托给子类,用来生产同一等级结构中的固定产品。(支持拓展增加产品)   
  3. 抽象工厂 :对象的创建实现在工厂接口所暴露的方法中,用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)  

四、三种工厂方式总结:
1、对于简单工厂和工厂方法来说,两者的使用方式实际上是一样的,如果对于产品的分类和名称是确定的,数量是相对固定的,推荐使用简单工厂模式;
2、抽象工厂用来解决相对复杂的问题,适用于一系列、大批量的对象生产;

注意事项

  (1)工厂类常常采用单例模式(Singleton)。

  (2)工厂类拥有基类(定义共同接口)。

工厂模式可以帮助我们针对抽象/接口编程,而不是针对具体类编程,在不同的场景下按具体情况来使用。

获取文章中完整代码示例可访问github:https://github.com/grayee/ecms/tree/master/ecms-web/src/test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值