大家好,欢迎来到程序视点!
前言
在上一节的简单工厂模式中,我们知道简单工厂所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
也就是说,类的创建依赖工厂类,如果想要拓展程序(添加新的类),必须对工厂类进行修改。这违背了开闭原则。
从设计角度考虑,有一定的问题,如何解决?
既然要遵循【开闭原则】,工厂类肯定是不能修改了。那就只能用新的工厂来创建新的类–具体的类由具体的工厂来创建
.
新添加的“具体的类”可能是不确定的,可能是“XiaomiPhone”,也有可能是“OppoPhone”,还可能是未来会出现的“XXXPhone”…那它们对应的工厂类就应该有“XiaomiPhoneFactory”,“OppoPhoneFactory”,“XXXPhoneFactory”…
我们把这些工厂类进一步抽象,就形成了我们接下来要讲的工厂方法模式
工厂方法模式简介
定义一个创建对象的抽象方法,且可以创建多个不同的工厂类实现该抽象方法。要创建某个具体的类,就新增一个具体的工厂类;这个工厂类通过实现抽象方法来创建类。这就是我们说的工厂方法模式
。
这样的好处就是:想要新创建一个类,不用修改原来的类,而是自己新建一个属于自己的工厂类。
从上面的描述中,我们可以抽象出这么几个角色:
- 抽象工厂:用来声明抽象方法的。 返回值就是产品抽象类。
- 产品类工厂:专门生产某个具体产品的工厂类。
- 产品抽象类:工厂类能创建出来的所有产品类的抽象。它负责描述所有实例所共有的公共接口。(这里必须要一个抽象类,不然不能保证返回的不同的产品类属于同一个类型)
- 产品类:工厂类创建出来的目标。它(们)是产品抽象类的具体实现。
示例
抽象工厂:
public interface PhoneFactory { public Phone createPhone();}
怎么是个接口呢?只有抽象方法的类,当然可以声明为接口呀!
产品类工厂:“HuaweiPhoneFactory”和“ApplePhoneFactory”
public class HuaweiPhoneFactory implements PhoneFactory { public Phone createPhone() { return new HuaweiPhone(); }}
public class ApplePhoneFactory implements PhoneFactory { public Phone createPhone() { return new ApplePhone(); }}
让我们来测试下:
public class Test { public static void main(String[] args) { PhoneFactory huaweiPhoneFactory = new HuaweiPhoneFactory(); Phone phone1 = huaweiPhoneFactory.createPhone(); System.out.println(phone1.info()); PhoneFactory applePhoneFactory = new ApplePhoneFactory(); Phone phone2 = applePhoneFactory.createPhone(); System.out.println(phone2.info()); }}
输出:
我是华为手机
我是苹果手机
咿呀!和简单工厂模式一样的呐!
现在我们要创建“小米手机”啦
新增一个 XiaomiPhone 的实体类:
public class XiaomiPhone implements Phone{ @Override public String info() { return "我是小米手机"; }}
新增一个创建 XiaomiPhone 对象的工厂类:
public class XiaomiPhoneFactory implements PhoneFactory { public Phone createPhone() { return new XiaomiPhone(); }}
测试一下:
public class Test { public static void main(String[] args) { PhoneFactory xiaomiPhoneFactory = new XiaomiPhoneFactory(); Phone phone3 = xiaomiPhoneFactory.createPhone(); System.out.println(phone3.info()); }}
输出:
我是小米手机
哈哈!我们没有修改之前的HuaweiPhoneFactory或ApplePhoneFactory两个工厂类,通过新增XiaomiPhoneFactory工厂类的方式来生产新的XiaomiPhone
🆗,这样我们就完成了工厂方法模式
创建和使用。
工厂方法模式的问题
工厂方法模式有什么问题呢?我们先来看一个场景:
现在“华为”和“苹果”都要开始生产电脑了。“华为”只能生产“华为电脑”,“苹果”只能生产“苹果电脑”。
按照上述的工厂方法模式,那就必然对应的抽象类、实体抽象类、实体类和实体工厂类。
抽象工厂:
public interface ComputerFactory { public Computer createComputer();}
public abstract class Computer { public abstract String getName();}
public class HuaweiComputer extends Computer{ @Override public String getName() { return "我是华为电脑"; }}
public class AppleComputer extends Computer{ @Override public String getName() { return "我是苹果电脑"; }}
产品类工厂:“HuaweiComputerFactory”和“AppleComputerFactory”
public class HuaweiComputerFactory implements ComputerFactory { public Computer createComputer() { return new HuaweiComputer(); }}
public class AppleComputerFactory implements ComputerFactory { public Computer createComputer() { return new AppleComputer(); }}
🆗,Cool!我们一下就搞定了!
接着,“华为”和“苹果”都要开始生产智能手表了。“华为”只能生产“华为手表”,“苹果”只能生产“苹果手表”。
再接着,“华为”和“苹果”都要开始生产音响了。“华为”只能生产“华为音响”,“苹果”只能生产“苹果音响”。
…耳机,服务器,汽车等等
哇!随着产品类的增多,我们的工厂类似乎也增加了。这还不重要的,问题出在下面:
突然,我们要进行手机和电脑配对链接了!
public class Test { public static void main(String[] args) { PhoneFactory huaweiPhoneFactory = new HuaweiPhoneFactory(); Phone phone1 = huaweiPhoneFactory.createPhone(); PhoneFactory applePhoneFactory = new ApplePhoneFactory(); Phone phone2 = applePhoneFactory.createPhone(); ComputerFactory huaweiComputerFactory = new HuaweiComputerFactory(); Computer computer1 = huaweiComputerFactory.createComputer(); ComputerFactory appleComputerFactory = new AppleComputerFactory(); Computer computer2 = appleComputerFactory.createComputer(); // 匹配 match(phone1, computer2); } public static void match(Phone p, Computer c) { System.out.println(p.info() + "===" + c.getName()) }}
输出:
我是华为手机===我是苹果电脑
看到了?华为手机匹配连接到苹果电脑上了!
大家知道问题了吗?怎么解决这个问题呢?我们下期见!
更多信息,请关注同名公众号【程序视点】,提前预览~