精通设计模式之工厂方法模式

工厂方法模式

工厂方法模式又被称为虚拟构造器(Virtual Constructor)

作用

定义用于创建对象的接口,但是让子类决定要实例化哪个类。工厂方法将类实例化推迟到子类。

说明

真实案例

  1. 铁匠制造武器。精灵需要精灵武器和兽人需要兽医武器。根据手头的客户,正确的类型的铁匠被召唤。
  2. 发送器发送信息。短信发送器发送短信息和邮件发送器发送邮件信息。根据业务需求,调用正确类型的发送器发送信息。

简而言之

工厂方法模式提供了一种将实例化逻辑委托给子类的方法

维基百科定义

在基于类的编程中,工厂方法模式是使用工厂方法来处理创建对象的问题的创建模式,而不必指定将要创建的对象的确切类。这可以通过调用工厂方法(在接口中指定并由子类实现)来实现,或者在基类中实现,并且可选地被派生类覆盖,而不是调用构造函数。

程序示例

以我们的信息发送器为例。首先我们有一个信息发送器接口和一些实现

/**
 * Description: 定义发送者接口
 * <br /> Author: vimx86
 */
public interface Sender {

    /**
     * 发送信息
     */
    void send();

}

/**
 * Description: 邮件发送者
 * <br /> Author: vimx86
 */
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("邮件发送者发送了一封邮件!");
    }
}

/**
 * Description: 短信息发送者
 * <br /> Author: vimx86
 */
public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("短信息发送者发送了一封邮件!");
    }
}

定义信息发送器生产工厂

/**
 * Description: 发送工厂(普通工厂模式)
 * <br /> Author: vimx86
 */
public class SimpleSendFactory {

    /**
     * 根据发送者类型名称生产对应发送者
     *
     * @param type 发送者类型
     * @return 具体发送者
     */
    public Sender produce(String type) {
        if ("mail".equals(type)) {
            return new MailSender();
        } else if ("sms".equals(type)) {
            return new SmsSender();
        } else {
            System.out.println("请输入正确的类型!");
            return null;
        }
    }

}

现在,根据发送器类型调用正确的信息发送器并发送信息。

/**
 * Description: 测试普通工厂模式
 * <br /> Author: vimx86
 */
public class SimpleSendFactoryTest {
    @Test
    public void test() throws Exception {
        SimpleSendFactory factory = new SimpleSendFactory();
        Sender sender = factory.produce("sms");
        sender.send();
    }
}

适用场景

何时使用“工厂方法”模式

  • 一个类不能预期它必须创建的对象类
  • 一个类希望其子类来指定它创建的对象
  • 类将责任委托给几个辅助子类之一,并且您想要本地化哪个助手子类是委托的知识

Known uses

点进去看一看,理解一下 ^_^!!!
* java.util.Calendar
* java.util.ResourceBundle
* java.text.NumberFormat
* java.nio.charset.Charset
* java.net.URLStreamHandlerFactory
* java.util.EnumSet
* javax.xml.bind.JAXBContext

信息发送案例

  • 普通工厂模式
  • 多个工厂方法模式
  • 静态工厂方法模式

工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。
在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,
第三种相对于第二种,不需要实例化工厂类,
所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

工厂方法模式的运用

结合实际业务进行分析运用设计案例

业务场景

获取不同票务商(大众,猫眼,蜘蛛等等)提供的影院实时座位图。
考虑业务扩展,保证有新票务商的接入时不影响当前业务。提供扩展性,可维护性。

分析设计

因为每家票务商都需要提供实时座位图功能,故可抽象出共同的接口 实时座位图提供商 提供实时座位图功能。

定义实时座位图提供商接口 RealTimeSeats 和实现具体票务商的子类。

public interface RealTimeSeats{
    /**
    * 获取实时座位图信息
    */
    RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest);
}

/**
 * Description: 猫眼获取实时座位图
 * <br /> Author: vimx86
 */
public class MaoYanRealTimeSeats implements RealTimeSeats{
    @Override
    public RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest) {
          // 猫眼获取实时座位图逻辑调用……
   }
}

/**
 * Description: 蜘蛛网获取实时座位图
 * <br /> Author: vimx86
 */
public class SpiderRealTimeSeats implements RealTimeSeats{
    @Override
    public RealtimeSeatModel getSeats(RealTimeSeatsRequest realTimeSeatsRequest) {
        // 蜘蛛网获取实时座位图逻辑调用……
    }
}

定义获取实时座位图工厂


/**
 * Description: 实时座位图工厂
 * <br /> Author: vimx86
 */
public class RealTimeSeatsFactory {

    public static RealTimeSeats produceSpider() {
        return new SpiderRealTimeSeats ();
    }

    public static RealTimeSeats produceMaoYan() {
        return new MaoYanRealTimeSeats ();
    }

}

这种工厂方法模式 扩展需要修改工厂类,等我们学习了抽象工厂模式再进一步改进。

参考资料

posted @ 2017-10-30 17:40  valuenovel  阅读(189)  评论(0编辑  收藏  举报