每天一个设计模式之工厂方法模式

时间:2022-10-02 15:59:48

什么是“工厂方法模式”

工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

我们来看看工厂方法模式的UML图:

每天一个设计模式之工厂方法模式

从类图中我们可以看到,工厂方法有两个平行的接口(抽象类),一个是Product,一个是Factory

他们具体什么意思呢, 我们可以先来看看例子,然后再理解这个类图。

为什么要使用“工厂方法模式”

背景:假如我们需要使用 Java 生产很多款手机, 那么我们最传统最简单的做法似乎是这样子:

 public Phone createPhone(String name){
        if (name.equals("小米")){
            phone = new XiaoMiPhone();
        }else if (name.equals("华为")){
            phone = new HuaWeiPhone();
        }else if (...)
    }

这样做貌似没什么不对,但是我们可以仔细想想,假如我们需要生产更多品牌的手机呢?再加入我们需要不同国家生产适合该国家的手机呢(比如港版、美版等等)? 出现这类需求的时候, 我们这么做就显得有些力不从心了。

这个时候, 工厂方法模式就该登场了。

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

  1. 根据类图,我们首先需要两个顶层的接口

    /** * 手机的抽象类 * */
    public abstract class Phone {
    
       public String name;
       public double price;
    
       public abstract void showPhone();
    }
    
    
    
    /** * 工厂的抽象类 * */
    public abstract class PhoneFactory {
    
       public abstract Phone createPhone(String name);
    
    }
  2. 有了顶层接口,我们需要具体的手机类

    //华为
    public class HuaWeiPhone extends Phone {
       public HuaWeiPhone(String name, double price) {
           super.name = name;
           super.price = price;
       }
    
       @Override
       public void showPhone() {
           System.out.println("华为被生产出来啦=============");
           System.out.println(name + ": " + price);
       }
    }
    
    
    //小米
    public class XiaoMiPhone extends Phone {
       public XiaoMiPhone(String name, double price) {
           super.name = name;
           super.price = price;
       }
    
       @Override
       public void showPhone() {
           System.out.println("小米被生产出来啦=============");
           System.out.println(name + ": " + price);
       }
    }
    
    //Iphone
    public class IPhone extends Phone {
       public IPhone(String name, double price) {
           super.name = name;
           super.price = price;
       }
    
       @Override
       public void showPhone() {
           System.out.println("苹果被生产出来啦=============");
           System.out.println(name + ": " + price);
       }
    }
  3. 有了具体的手机类之后,我们就可以把具体的工厂创建出来了

    /** * 某个国家的工厂 */
    public class PhoneFactoryImpl extends PhoneFactory {
       Phone phone;
    
       @Override
       public Phone createPhone(String name) {
           if (name.equals("华为")){
               phone = new HuaWeiPhone(name,3999.99);
           }else if (name.equals("小米")){
               phone = new XiaoMiPhone(name,2999.99);
           }else if (name.equals("苹果")){
               phone = new IPhone(name,6999.99);
           }
           return phone;
       }
    }

    在这个方法中,其实可以使用反射技术实现在运行时动态地创建相应的对象,这样就可以在新增某款手机的时候避免修改代码。但是为了简单起见,我们在这里不使用反射技术,直接使用原始的方法。

  4. 所有东西都准备齐全了, 我们可以生产手机了。

    public class CreatePhoneTest {
    
       public static void main(String[] args){
           Phone phone;
    
           PhoneFactory factory = new PhoneFactoryImpl();
           phone = factory.createPhone("小米");
           phone.showPhone();
    
           phone = factory.createPhone("苹果");
           phone.showPhone();
    
           phone = factory.createPhone("华为 ");
           phone.showPhone();
       }
    }
  5. 运行结果如下:

    小米被生产出来啦=============
    小米: 2999.99
    苹果被生产出来啦=============
    苹果: 6999.99
    华为被生产出来啦=============
    华为: 3999.99

    在这个例子中, 我们只实现了一种具体的工厂, 假如需要不同的工厂生产不同类型的手机, 工厂方法模式无疑提供了很大的便利和可拓展性。

那么, 总结来了

在上面的例子中, 我想各位同学也都理解了UML类图的具体含义。

工厂方法模式是一种很实用、 拓展性强的模式。

优点:

  1. 封装性强: 我们只需要知道某个手机类或者手机名字的约束字符串,就可以进行生产。(本例中还需要去工厂实现类中添加一个判断分支,在具体的应用场景中我想没人会使用判断分支在工厂类中,一般都是使用反射)

  2. 拓展性好:比如我们还需要增加一款魅族手机,那么我们只需要实现 MeiZuPhone 类就可以了。

  3. 屏蔽了产品类:这一点非常有用,屏蔽了手机内部的具体实现, 只需要知道他们实现了 Phone 接口就行了。

使用场景:

工厂方法模式是 new 一个对象的替代品, 所以在需要新建一个对象的时候都可以使用, 但是要考虑使用后代码的复杂度。

与工厂方法模式类似的抽象工厂模式将在下一篇文章发表。欢迎关注


感谢阅读本博客。

欢迎关注我的博客:https://li-weijian.github.io/

欢迎关注我的CSDN:https://blog.csdn.net/qq352642663

需要联系请加QQ:352642663

欢迎联系我共同交流