工厂的模式们

原创 2016年08月09日 13:51:28

1.DIY

没有工厂的年代,客户需要自己造打印机:

public class PrinterLgl {
    private String name = null;

    public PrinterLgl(String name) {
        this.name = name;
        System.out.println("New: I'm " +
                this.getClass().getName() + " " + name);
    }
}
public class PrinterLhb {
    private String name = null;

    public PrinterLhb(String name) {
        this.name = name;
        System.out.println("New: I'm " +
                this.getClass().getName() + " " + name);
    }
}

客户需要知道怎么去创建一款打印机,客户和打印机就紧密耦合在一起了。

public class TestDIY {
    public static void main(String[] args) {
        PrinterLgl plgl1 = new PrinterLgl("puppy");
        PrinterLgl plgl2 = new PrinterLgl("guilin");

        PrinterLhb plhb1 = new PrinterLhb("haibao");
        PrinterLhb plhb2 = new PrinterLhb("haitiao");
    }
}

为了降低耦合,就出现了工厂类。

2.SimpleFactory

首先,打印机需要有个抽象类:

abstract class Printer {
    protected String name = null;

    public Printer() {
    }
}

然后,所有的打印机都继承这个类,具体产品:

public class PrinterLgl extends Printer {
    public PrinterLgl(String name) {

        this.name = name;
        System.out.println("New: I'm " +
                this.getClass().getName() + " " + name);
    }
}
public class PrinterLhb extends Printer {
    public PrinterLhb(String name) {

        this.name = name;
        System.out.println("New: I'm " +
                this.getClass().getName() + " " + name);
    }
}

再造一个工厂:

public class SimpleFactory {
    public Printer createPrinter(String brand, String name) {
        switch (brand) {
            case "lgl" :
                return new PrinterLgl(name);
            case "lhb" :
                return new PrinterLhb(name);
            default :
                System.out.println("New Printer " + name + " fails!");
                return null;
        }
    }
}

接着客户就可以直接提打印机了:

public class TestSimpleFactory {
    public static void main(String [] args) {
        SimpleFactory sf = new SimpleFactory();
        Printer plgl1 = sf.createPrinter("lgl", "puppy");
        Printer plgl2 = sf.createPrinter("lgl", "guilin");

        Printer plhb1 = sf.createPrinter("lhb", "haibao");
        Printer plhb2 = sf.createPrinter("lhb", "haitiao");

        Printer pnull = sf.createPrinter("lll", "liu");
    }
}

只需要先实例化一个工厂,再用工厂去生产打印机就好了。
这里用到了向上转型,eg:Printer p = new PrinterLgl(name),进而可以实现多态。
但是简单工厂显然有很多弊端:
最直观的来讲,它违反了开闭原则对扩展开放,对修改封闭
即每当需要增加一种打印机的时候,需要修改SimpleFactory类,增加case语句。而根据开闭原则,“修改”是不合适的。
而且每次在创建打印机的时候,还需要传一个brand参数。

3.FactoryMethod

刚刚的简单工厂,在添加新的打印机的时候不需要修改已有的打印机类,但需要修改工厂类。

简单工厂模式中的工厂,虽然号称简单工厂,但是实际上是一个“全能类”!
==> 产品是一个多层次的树状结构。而简单工厂模式中只有一个工厂类来对应这些产品。
显然全能类会吃不消。

仔细想想,打印机都继承了共同的抽象类。那么如果工厂也有一个抽象类,是不是就行了?
==> 将工厂类定义成接口,而每新增打印机的类型,就增加该打印机类型对应工厂类的实现。
这样工厂的设计就可以扩展了,而不必去修改原来的代码。

那么现在有:抽象产品,具体产品;抽象工厂,具体工厂。

抽象工厂使用抽象类和接口都可以:

public interface FactoryPrinter {
    Printer createPrinter(String name);
}

具体的工厂:

public class FactoryLgl implements FactoryPrinter {

    @Override
    public Printer createPrinter(String name) {
        return new PrinterLgl(name);
    }
}
public class FactoryLhb implements FactoryPrinter {

    @Override
    public Printer createPrinter(String name) {
        return new PrinterLhb(name);
    }
}

而打印机同之前一样,这里不再列出。
测试:

public class TestFactoryMethod {
    public static void main(String[] args) {
//        FactoryLgl flgl = new FactoryLgl();
        FactoryPrinter flgl = new FactoryLgl();
        Printer plgl1 = flgl.createPrinter("puppy");
        Printer plgl2 = flgl.createPrinter("guilin");

//        FactoryLhb flhb = new FactoryLhb();
        FactoryPrinter flhb = new FactoryLhb();
        Printer plhb1 = flhb.createPrinter("haibao");
        Printer plhb2 = flhb.createPrinter("haitiao");
    }
}

如果再有新的打印机,增加一个新的implements了FactoryPrinter接口的类就好了。
不必修改已有的工厂的代码。符合开闭原则。
这个工厂也叫多态工厂。

缺陷:当产品太多时,工厂也会疯长。这个时候,可以使用抽象工厂模式将一些产品组合起来,使用同一个工厂来生产,而不用为每一种产品都新建一个工厂。

4.AbstractFactory

现在假设每一种打印机都需要使用本打印机特有的油墨类型:
那么打印机这种产品不用变,仿照打印机增加一种新的产品,Ink。
抽象类:

abstract class Ink {
    public Ink() {
    }
}

具体油墨:

public class InkA extends Ink {
    public InkA() {
        System.out.println("New: I'm " + this.getClass().getName());
    }
}
public class InkB extends Ink {
    public InkB() {
        System.out.println("New: I'm " + this.getClass().getName());
    }
}

工厂原来只生产一种产品:打印机。现在生产两种:打印机和其所需要的墨水。
工厂接口:

public interface AbstractFactory {
    Printer createPrinter(String name);
    Ink createInk();
}

具体工厂:

public class FactoryLgl implements AbstractFactory {

    @Override
    public Printer createPrinter(String name) {
        return new PrinterLgl(name);
    }

    @Override
    public Ink createInk() {
        return new InkA();
    }
}
public class FactoryLhb implements AbstractFactory {

    @Override
    public Printer createPrinter(String name) {
        return new PrinterLhb(name);
    }

    @Override
    public Ink createInk() {
        return new InkB();
    }
}

然后就可以测试了:

public class TestAbstractFactory {
    public static void main(String[] args) {
//        FactoryLgl flgl = new FactoryLgl();
        AbstractFactory flgl = new FactoryLgl();
        Printer plgl1 = flgl.createPrinter("puppy");
        Ink ilgl1 = flgl.createInk();
        Printer plgl2 = flgl.createPrinter("guilin");
        Ink ilgl2 = flgl.createInk();

//        FactoryLhb flhb = new FactoryLhb();
        AbstractFactory flhb = new FactoryLhb();
        Printer plhb1 = flhb.createPrinter("haibao");
        Ink ilhb1 = flhb.createInk();
        Printer plhb2 = flhb.createPrinter("haitiao");
        Ink ilhb2 = flhb.createInk();
    }
}

缺陷:当新增加一种打印机和它的油墨的时候,只需要用一个新的工厂public class FactoryXXX implements AbstractFactory就可以了,无需修改原来工厂的代码,符合开闭原则。但是如果新增加一种产品,比如需要生产打印机+打印机需要的墨水+打印机所需要的纸张,这个时候整个AbstractFactory需要增加一种新的生成纸张的方法,所有的实体工厂也都需要新增这种方法。这可以称为“开闭原则的倾斜性”,不能兼顾所有情况下都满足开闭原则。

总结:
抽象工厂就是生产一个产品族(Product Family),比如打印机+墨水。
如果产品族退化为一个产品,比如只生产打印机,抽象工厂就退化成了工厂方法模式。

如果工厂方法模式再进行简化,由多个工厂变成只有一个工厂,那就是简单工厂模式。

在简单工厂模式时,可以将工厂生产产品的方法设置为静态的,在测试类中需要生成产品的时候,直接SimpleFactory.createPrinter()就好了。反正就这一个工厂。

但是在工厂方法模式和抽象工厂模式中,必须不能设置为静态的。
因为因为工厂方法是抽象方法,要求由子类来动态地实现,而动态性与static所声明的静态性相冲突。

版权声明:本文为博主原创文章,未经博主允许不得转载。

对工厂模式的简单理解

简单工厂模式: 一个工厂类+一个抽象产品类+多个具体产品类 这个工厂类负责多个具体产品类的创建 由于只有一个工厂类,所以需要扩充时只能修改工厂类,不符合开闭原则。工厂模式: 一个抽象工厂类+多...
  • weixin_36184484
  • weixin_36184484
  • 2017年08月06日 18:14
  • 97

java实现的注册工厂模式

package com.eric.reflect; import java.util.ArrayList; import java.util.Random; /* * factory interf...
  • sun7545526
  • sun7545526
  • 2012年02月07日 22:08
  • 2054

个人对工厂模式的理解

使用工厂模式 创建对应的对象,以避免对原始代码的修改  //面向接口public class star {       /**        * @param args        */      ...
  • dagao
  • dagao
  • 2009年05月09日 17:16
  • 124

Java注册工厂模式案例

public Interface factory{ T create(); } package chapter14.factory; import java.util.ArrayL...
  • u012521360
  • u012521360
  • 2015年01月09日 01:23
  • 286

11.[个人]C++线程入门到进阶(11)----生产者消费者经典问题

继经典线程同步问题之后,我们来看看生产者消费者问题及读者写者问题。生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消...
  • shuimanting520
  • shuimanting520
  • 2017年04月25日 23:32
  • 193

[camera drv]工厂模式下测试camera fail

[DESCRIPTION] 1. 工厂模式下测试camera失败,从工厂模式下的android log里面有以下关于M4U的log出现: E/M4U_L   (   90): Open file ...
  • andylao62
  • andylao62
  • 2013年01月03日 11:04
  • 1716

Java Dao工厂设计模式

这里简要说明Java中的分层设计思想。如下图所示: 将功能的实现分在两层进行,访问层和业务层。 (1)设计IDao接口 package web.java.xml.model; public i...
  • tao_sun
  • tao_sun
  • 2013年06月01日 09:42
  • 2142

给工厂分配销售组织/分销渠道

一.说明 在SAP系统做销售,需将销售组织/分销渠道的组合与工厂进行关联,其中前者的组合用于销售业务,而后者(工厂)用于交货。销售组织/分销渠道组合下可以有多个工厂;一个工厂可以分配给多个销售组...
  • zhongguomao
  • zhongguomao
  • 2017年06月14日 15:30
  • 508

C++插件机制的一种实现方法(对象工厂)

背景 在我们的实际开发过程中,经常会开发一些插件,比较常见的例子如:给你 DataHandler,它是一个抽象类,提供一些数据操作的接口,然后插件开发者就需要继承DataHandler,并按需求...
  • lclflash
  • lclflash
  • 2013年04月26日 22:49
  • 811

三个工厂模式的分析

简单工厂模式抽象出了一个业务逻辑的父类,父类定义了定义了属性和方法,子运算类只需要重写运算方法即可。...
  • u010942465
  • u010942465
  • 2014年05月23日 09:27
  • 1437
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:工厂的模式们
举报原因:
原因补充:

(最多只允许输入30个字)