建立多个“产品”的方式——工厂方法模式总结

简单工厂模式严格来讲不算一个设计模式——缺点

继续说以前提到的简单工厂模式,严格来讲,这不算一个设计模式……并且在业务量比较多了以后,它也有诸多的隐患程序员

一、因为工厂类集中了全部实例的建立逻辑,这就直接致使一旦这个工厂出了问题,全部的客户端都会受到牵连设计模式

二、因为简单工厂模式的产品基于一个共同的抽象类或者接口,这样一来,产品的种类增长的时候,即有不一样的产品接口或者抽象类的时候,简单工厂类就须要维护大量的if-else判断,好比导入导出功能,虽然能够用反射或者配置文件,注解等解耦,可是还有更好的办法。app

不使用工厂方法模式的例子

仍是举那个水果的例子:以前水果园子里只有苹果和香蕉两种水果,如今又新加一个梨的品种。简单工厂类的代码以下:ide

// 简单工厂类
public class FruitFactoryA {
    public static FruitA getFruit(String type) {
        if ("apple".equalsIgnoreCase(type)) {
            return new AppleA();
        } else if ("banana".equalsIgnoreCase(type)) {
            return new BananaA();
        } else if ("pear".equalsIgnoreCase(type)) {
            return new PearA();
        } else {
            System.out.print("error!");
        }

        return null;
    }
}

该例子使用简单工厂模式,工厂类过于臃肿。ui

public class Main {
    public static void main(String[] args) {
        FruitA apple = FruitFactoryA.getFruit("apple");
        FruitA banana = FruitFactoryA.getFruit("banana");
        FruitA pear = FruitFactoryA.getFruit("pear");

        // 不太好,没有检测null异常,演示
        apple.get();
        banana.get();
        pear.get();
    }
}

由于简单工厂模式只有一个工厂类,它须要处理全部的对象建立的逻辑。若是往后需求不断增长,则后果不堪设想,违背了单一职责,致使系统丧失灵活性和可维护性。并且更重要的是,简单工厂模式违背了OCP——开放封闭原则。固然还有单一职责原则(虽然这里没具体体现)。那么如何改进呢?spa

引入工厂方法模式——让子类去建立对象

如何才能实现工厂类的代码不去修改,而开放扩展——能够把工厂的职责抽象,抽象if-else判断逻辑,把每个判断都抽象为一个工厂类,而这些具体的工厂类统一抽象为一个接口来约束具体子类去生产产品,这就是传说中的——工厂方法模式,它一样属于类的建立型模式,又被称为多态工厂模式。设计

工厂方法模式的意义是定义一个建立产品对象的工厂接口,将实际建立工做推迟到子类当中。核心工厂类再也不负责产品的建立,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口(仅仅起到一个约束生产动做的做用),这样进一步抽象化的好处是使得工厂方法模式可使系统在不修改具体工厂角色的状况下引进新的产品。code

工厂方法模式实现

抽象工厂角色:工厂方法模式的核心,任何工厂类都必须实现这个接口对象

public interface FactoryA {
    FruitA getFruit();
}

具体工厂( Concrete  Creator)角色;具体工厂类是抽象工厂的一个实现,负责实例化产品对象blog

public class AppleFactoryA implements FactoryA {
    @Override
    public FruitA getFruit() {
        return new AppleA();
    }
}

public class BananaFactoryA implements FactoryA {
    @Override
    public FruitA getFruit() {
        return new BananaA();
    }
}

public class PearFactory implements FactoryA {
    @Override
    public FruitA getFruit() {
        return new PearA();
    }
}

抽象产品(Product)角色;工厂方法模式所建立的全部对象的父类,它负责描述全部实例所共有的公共接口

public interface FruitA {
    void get();
}

具体产品(Concrete Product)角色;工厂方法模式所建立的具体实例对象

public class AppleA implements FruitA {
    @Override
    public void get() {
        System.out.println("苹果");
    }
}

public class BananaA implements FruitA {
    @Override
    public void get() {
        System.out.println("香蕉");
    }
}

public class PearA implements FruitA {
    @Override
    public void get() {
        System.out.println("梨");
    }
}

客户端调用

public class Main {
    public static void main(String[] args) {
        // 获得对应的水果的工厂
        FactoryA appleF = new AppleFactoryA();
        FactoryA bananaF = new BananaFactoryA();
        FactoryA peatF = new PearFactory();

        // 经过各个工厂去获得对应的水果
        FruitA apple = appleF.getFruit();
        FruitA banana = bananaF.getFruit();
        FruitA pear = peatF.getFruit();

        apple.get();
        banana.get();
        pear.get();
    }
}

如上代码,若是之后有新的水果出现,好比橘子,那么不用修改工厂类,只须要增长一个橘子以及橘子的工厂类,且橘子工厂同时去遵循工厂的接口便可,客户端调用就能够了,而其余已经写好的工厂类无需修改!彻底符合OCP原则,同时每一个具体工厂子类只负责对应水果的生成,也遵照了单一职责原则

类图以下

简单工厂和工厂方法模式对比

工厂方法模式与简单工厂模式在结构上的不一样不是很明显。

一、工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。

二、工厂方法模式之因此有一个别名叫多态性工厂模式,是由于具体工厂类都有共同的接口,或者有共同的抽象父类。

系统扩展须要添加新的产品对象时,仅仅须要添加一个具体对象以及一个具体工厂对象,原有工厂对象不须要任何修改,也不须要修改客户端原有的代码,很好的符合了“开放-封闭”原则。

而简单工厂在添加新产品对象后,不得不修改工厂方法,扩展性很差。

工厂方法模式退化后能够演变成简单工厂模式。

JDK 中的工厂方法模式

JAVA的 API 里使用了工厂方法模式的也不少不少,经常使用的好比,Object 类里的 toString() 方法,Java 的任何类,均可以继承或者覆写toString 方法,Object 至关于抽象工厂类,各个Java 的类,至关于具体工厂类。

还有 util 包里的Calendar类,该类是一个抽象类,它为特定瞬间与一组诸如 YEARMONTHDAY_OF_MONTHHOUR 等日历字段之间的转换提供了一些方法,并为操做日历字段(例如得到下星期的日期)提供了一些方法。

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
    public static Calendar getInstance() {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }
}

该节选的代码片断有一个静态的 getInstance() 方法,return 了一个具体的日历对象,Calendar 是工厂方法模式里的抽象工厂类,而具体工厂子类(简单举几个例子)有JapaneseImperialCalendar,GregorianCalendar……

createCalendar 方法是 private 的,是属于 getInstance 方法里的,也就是说 Calendar 这个抽象工厂类返回具体子类的对象,JDK 里这样说:

与其余语言环境敏感类同样,Calendar 提供了一个类方法 getInstance,以得到此类型的一个通用的对象。Calendar 的 getInstance 方法返回一个 Calendar 对象,其日历字段已由当前日期和时间初始化……

客户端经过该方法返回对应的日历工厂,客户端再经过这些日历工厂去生成对应的日历产品……未来若是须要支持某个其余地区的特殊历法,程序员除了必要的增长对应的日历工厂并 extends Calendar 这个抽象工厂,且增长对应的日历产品以外,只须要增长 Calendar 的 getInstance 方法的新的逻辑,但 Calendar 的使用者无需承担这种变化的影响,符合OCP。

相关文章
相关标签/搜索