设计模式-简单工厂模式

模式定义

简单工厂模式是属于建立型模式,又叫作静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式定义了一个建立对象的类,由这个类来封装实例化对象的行为。java

设计原则

遵循的原则:编程

  • 依赖倒置原则
  • 迪米特法则
  • 里氏替换原则
  • 接口隔离原则

未遵循的原则设计模式

  • 开闭原则
  • 单一职责原则

UML类图

简单工厂模式类图

简单工厂模式实例

问题描述ide

Pizza 类有不少子类,要求根据不一样的状况用不一样的子类实例化一个 Pizza 对象。工具

首先咱们定义披萨接口测试

package com.wpx.simplefactory;

/**
 * 定义披萨接口
 */
public interface Pizza {
    public void make();
}

接着,定义两个具体的披萨类,乳酪比萨和希腊披萨设计

package com.wpx.simplefactory;

/**
 * 具体的披萨-乳酪比萨
 */
public class CheesePizza implements Pizza {

    @Override
    public void make() {
        System.out.println("乳酪比萨");
    }
}
package com.wpx.simplefactory;

/**
 * 具体的披萨-希腊披萨
 */
public class GreekPizza implements Pizza {

    @Override
    public void make() {
        System.out.println("希腊披萨");

    }
}

紧接着,咱们定义一个披萨工厂来生产披萨code

package com.wpx.simplefactory;

/**
 * 披萨工厂类
 */
public class SimplePizzaFactory {
    public static Pizza createPizza(String type) {
        if (type.equals("乳酪比萨")) {
            return new CheesePizza();
        } else if (type.equals("希腊披萨")) {
            return new GreekPizza();
        } else {
            throw new UnsupportedOperationException();
        }
    }
}

如今一个基于简单工厂模式的披萨工厂就建造完成了,咱们对此进行测试,让披萨工厂来一份乳酪披萨尝尝。orm

package com.wpx.simplefactory;

/**
 * 测试简单工厂模式-披萨工厂
 */
public class PizzaStore {
    public static void main(String[] args) {
        Pizza pizza = SimplePizzaFactory.createPizza("乳酪比萨");
        pizza.make();
    }
}

运行结果对象

乳酪比萨

Process finished with exit code 0

java.text.DateFormat中的简单工厂模式

DateFormat:jdk中的一个工具类java.text.DateFormat,用来格式化一个本地日期与时间

经过源码咱们能够知道DateFormat是一个抽象类(abstract),下面的源代码就是这个类里包含的方法,其实这些就是静态工厂方法,经过静态方法来提供本身的实例是彻底能够的(抽象类自己不能进行实例化)。从源码能够看出getDateInstance()方法作了两件事情:

  1. 运用了多态性:因为SimpleDateFormat是DateFormat的子类,而getDateInstance()声明的类型为DateFormat而实际返回类型为子类SimpleDateFormat
  2. 使用了静态工厂方法(static):因为DateFormat是抽象类不能进行实例化,所以也就不能调用其中的普通方法(非静态方法)。所以咱们必须将其声明为static,才能返回实例

经过上面作的两件事情就将具体子类的实例化过程隐藏起来了,调用者没必要考虑具体子类的实例化,由于抽象类会提供它的合适子类实例

public final static DateFormat getDateInstance()
    {
        return get(0, DEFAULT, 2, Locale.getDefault());
    }

    public final static DateFormat getDateInstance(int style)
    {
        return get(0, style, 2, Locale.getDefault());
    }

    public final static DateFormat getDateInstance(int style,
                                                 Locale aLocale)
    {
        return get(0, style, 2, aLocale);
    }
    
    private static DateFormat get(int timeStyle, int dateStyle,
                                  int flags, Locale loc) {
        if ((flags & 1) != 0) {
            if (timeStyle < 0 || timeStyle > 3) {
                throw new IllegalArgumentException("Illegal time style " + timeStyle);
            }
        } else {
            timeStyle = -1;
        }
        if ((flags & 2) != 0) {
            if (dateStyle < 0 || dateStyle > 3) {
                throw new IllegalArgumentException("Illegal date style " + dateStyle);
            }
        } else {
            dateStyle = -1;
        }
        try {
            // Check whether a provider can provide an implementation that's closer 
            // to the requested locale than what the Java runtime itself can provide.
            LocaleServiceProviderPool pool =
                LocaleServiceProviderPool.getPool(DateFormatProvider.class);
            if (pool.hasProviders()) {
                DateFormat providersInstance = pool.getLocalizedObject(
                                                    DateFormatGetter.INSTANCE,
                                                    loc, 
                                                    timeStyle,
                                                    dateStyle,
                                                    flags);
                if (providersInstance != null) {
                    return providersInstance;
                }
            }

            return new SimpleDateFormat(timeStyle, dateStyle, loc);
        } catch (MissingResourceException e) {
            return new SimpleDateFormat("M/d/yy h:mm a");
        }
    }

总结

优势:

  • 将建立实例的工做与使用实例的工做分开,使用者没必要关心类对象如何建立,明确了职责。
  • 把初始化实例时的工做放到工厂里进行,使代码更容易维护。更符合面向对象的原则,面向接口编程,而不是面向实现编程。

缺点:

  • 因为工厂类集中了全部产品建立逻辑,一旦不能正常工做,整个系统都要受到影响。
  • 要新增产品类的时候,就要修改工厂类的代码,违反了开放封闭原则(对扩展的开放,对修改的关闭)。
  • 简单工厂模式因为使用了静态工厂方法,形成工厂角色没法造成基于继承的等级结构。
相关文章
相关标签/搜索