简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
简单工厂模式是工厂模式家族中最简单实用的模式
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式.
手机制造顶层接口
public interface Phone { void make(); }
小米制造商
public class XiaoMiPhone implements Phone { @Override public void make() { System.out.println("制造了一台小米手机"); } }
华为制造商
public class HuaWeiPhone implements Phone{ @Override public void make() { System.out.println("制造了一台华为手机"); } }
手机制造代工厂(富士康)
public class PhoneFactory { public Phone makePhone(String phoneType){ if ("xiaomi".equals(phoneType)){ return new XiaoMiPhone(); }else if ("huawei".equals(phoneType)){ return new HuaWeiPhone(); } return null; } }
用户需求方
public class TestMain { public static void main(String[] args) { PhoneFactory phoneFactory = new PhoneFactory(); Phone xiaomi = phoneFactory.makePhone("xiaomi"); xiaomi.make(); Phone huawei = phoneFactory.makePhone("huawei"); huawei.make(); } }
类图如下所示
简单工厂模式的缺点就在于
通过上面制造手机的列子可以看出,此时我们的工厂只能生产华为和小米两款手机
如果想要生辰更多的品牌手机,那就的在工厂中加条件适配
没增加一个手机品牌,就要去修改工厂的源码,这种操作不符合开闭原则
但是我们可以对其进行优化,使其符合开闭原则
// public Phone makePhone(String phoneType){ // if ("xiaomi".equals(phoneType)){ // return new XiaoMiPhone(); // }else if ("huawei".equals(phoneType)){ // return new HuaWeiPhone(); // } // return null; // } public Phone makePhoneOptimize(Class <? extends Phone> clazz){ if (null != clazz){ try { return clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return null; }
然后使用者对应的使用方式也跟着改变一下
// PhoneFactory phoneFactory = new PhoneFactory(); // Phone xiaomi = phoneFactory.makePhone("xiaomi"); // xiaomi.make(); // Phone huawei = phoneFactory.makePhone("huawei"); // huawei.make(); PhoneFactory phoneFactory = new PhoneFactory(); Phone xiaomi = phoneFactory.makePhoneOptimize(XiaoMiPhone.class); xiaomi.make(); Phone huawei = phoneFactory.makePhoneOptimize(HuaWeiPhone.class); huawei.make(); }
这样,即使我们继续扩展更多的品牌生产线,也可以不用动这一部分的源码了
简单工厂模式在很多地方都在使用,
比如日历类Calendar.getInstance()方法
或者logback中到 LoggerFactory 中有多个重载的方法 getLogger()
简单工厂的缺点就是,工厂类的职责相对过重,不易于扩展过于复杂的产品结构
和简单工厂模式相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,而不是由一个大工厂聚合生产
Phone 、XiaoMiPhone、HuaWeiPhone 类的不变
新增抽象工厂类、小米工厂类、华为工厂类即可
总工厂接口
public interface PhoneFactory { Phone makePhone(); }
小米工厂类
public class XiaoMiFactory implements PhoneFactory { @Override public Phone makePhone() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。像简单工厂模式一一致 return new XiaoMiPhone(); } }
华为工厂类
public class HuaWeiFactory implements PhoneFactory { @Override public Phone makePhone() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。像简单工厂模式一一致 return new HuaWeiPhone(); } }
用户需求方
public class TestMain { public static void main(String[] args) { PhoneFactory xiaoMiFactory = new XiaoMiFactory(); PhoneFactory huaWeiFactory = new HuaWeiFactory(); Phone xiaomi = xiaoMiFactory.makePhone(); Phone huawei = huaWeiFactory.makePhone(); xiaomi.make(); huawei.make(); } }
类图如下所示
工厂方法模式主要解决的是产品的扩展问题
在简单工程模式中,最后我们使用反射的方式实现开闭原则
但是如果没饿过课程的创建逻辑有区别的话,工厂的职责就会越加繁重,不利于维护
根据单一职责原则,我们可以将职能进行划分
最大的工厂只负责约束管理
其下允许动态创建其他干实事的小工厂
就比如富士康只负责谈需求,接单,产品验收
但其下的子工厂或者找个外包工厂(自由扩展)来干活
工厂方法模式和简单工厂的区别就在于
简单工厂只有一个工厂,负责产品的创建和销售
工厂方法模式,有一个最大的工厂负责制定规章制度,旗下有很多专一的小工厂来负责生产和销售
定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
上面的工厂模式都是在围绕手机在生产,如果这个时候,我们添加一个PC领域进去该如何玩呢?
手机制造顶级接口
public interface Phone { void make(); }
小米手机制造商
public class XiaoMiPhone implements Phone { @Override public void make() { System.out.println("制造了一台小米手机"); } }
华为手机制造商
public class HuaWeiPhone implements Phone { @Override public void make() { System.out.println("制造了一台华为手机"); } }
笔记本制造顶级接口
public interface PC { void make(); }
小米笔记本制造商
public class XiaoMiPC implements PC{ @Override public void make() { System.out.println("生产了一台小米笔记本"); } }
华为笔记本制造商
public class HuaWeiPC implements PC{ @Override public void make() { System.out.println("生产了一台华为笔记本"); } }
代工厂顶级接口,如果有一些公共的方法可以抽取,也可以使用抽象类来创建
public interface AbstractFactory { Phone makePhone(); PC makePC(); }
小米代工厂制造接口
public class XiaoMiFactory implements AbstractFactory { @Override public Phone makePhone() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。想简答工厂模式一一致 return new XiaoMiPhone(); } @Override public PC makePC() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。想简答工厂模式一一致 return new XiaoMiPC(); } }
华为代工厂制造接口
public class HuaWeiFactory implements AbstractFactory { @Override public Phone makePhone() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。想简答工厂模式一一致 return new HuaWeiPhone(); } @Override public PC makePC() { // 这里的方式是:;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。 // 如果消费者知道自己想要什么产品,可以入参,用参数来区别对待生产不同的产品。想简答工厂模式一一致 return new HuaWeiPC(); } }
需求方
public class TestMain { public static void main(String[] args) { AbstractFactory xiaoMiFactory = new XiaoMiFactory(); AbstractFactory huaWeiFactory = new HuaWeiFactory(); Phone xiaomi = xiaoMiFactory.makePhone(); PC xiaomiPC = xiaoMiFactory.makePC(); Phone huawei = huaWeiFactory.makePhone(); PC huaweiPC = huaWeiFactory.makePC(); xiaomi.make(); xiaomiPC.make(); huawei.make(); huaweiPC.make(); } }
类图如下所示
此时,如果我们觉得手机和笔记本都已经玩腻了,想进军造车行业
定义造成顶级接口
定义造车品牌实现接口,比如小鹏汽车,蔚来汽车等
此时增加代工顶级接口一个允许生产汽车的行为,并写一个汽车代工厂即可工厂
扩展性就大大的增加了
抽象工厂非常完美清晰地描述这样一层复杂的关系
小米公司可以生产手机和笔记本电脑
华为公司可以生成手机和笔记本电脑
如果此时我们还想继续追加他的功能职责,比如生产无人机
这个时候就要定义一个无人机的顶级接口
然后小米和华为都要再定义一个无人机的实现类
然后再在代工厂顶级接口中新增一个生产无人机的方法(开闭原则被破坏)
最后小米和华为的Factory,重写代工厂顶级接口中方法,实现无人机的生产(开闭原则被破坏)
使用的时候,如上方使用代码差异无二
因此抽象工程模式也是有很大缺点的,维护难度加大,理解难度加大
扩展时 - > 代工厂顶级接口需要维护
扩展时 - > 代工厂顶级接口的实现工厂也要维护实现对应方法
但是在实际应用中,我们新增一个功能职责的周期是很长的,只要不是频繁新增,这种设计模式仍然适合我们
抽象工厂模式在Spring中的应用是最为广泛的一种设计模式
工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
设计模式的依赖抽象原则
创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回
不要让类继承具体类,而是继承抽象类或者是实现 interface(接口)
Ø 不要覆盖基类中已经实现的方法。
.