前言
简单工厂模式不是一个标准的设计模式,也并不属于23种设计模式中的任何一种,但是它是抽象工厂模式和工厂方法模式的基础,且在日常工作中非常常见,姑且作为学习其他设计模式的热身吧。
文章讲解思路:设计模式本质就是一个解决方案。因此在后续的设计模式系列文章中,博主会首先给大家引出一个场景问题,并使用传统的面向过程编程方式解决,通过分析传统方案的弊端,并使用指定的设计模式进行优化改进,从而加深大家对设计模式及其设计理念的理解。同时也适当对设计模式进行扩展,剖析开源框架中的设计模式应用。(Java)
一、场景问题
目前市场手机品牌琳琅满目,包括华为、苹果、小米、vivo等。假设某厂家可以生产华为、苹果、小米这三种品牌的手机,请设计出一种厂家根据客户要求某品牌手机的解决方案。
二、解决方案
1、传统解决方案
1.1、代码实现
-
首先定义出产品的抽象接口
public interface Phone { /** * 产品描述 */ void desc(); }
-
根据接口定义出三种产品的原型,代码很简单。
//苹果手机 public class ApplePhone implements Phone{ @Override public void desc() { System.out.println("我是苹果手机"); } } //华为手机 public class HwPhone implements Phone{ @Override public void desc() { System.out.println("我是华为手机"); } } //小米手机 public class MiPhone implements Phone{ @Override public void desc() { System.out.println("我是小米手机"); } }
-
传统解决方案根据根据客户不同的需求,创建不同的手机实例,可以将用户的需求设置为参数传递,根据参数的不同创建不同的手机实例,代码也很简单
public class Client { public static void main(String[] args) { String phoneType = "huawei"; Phone phone = null; //根据不同的类型创建不同的手机实例 if ("apple".equals(phoneType)) { phone = new ApplePhone(); } else if ("xiaomi".equals(phoneType)) { phone = new MiPhone(); } else if ("huawei".equals(phoneType)) { phone = new HwPhone(); } else { throw new RuntimeException("不支持的手机品牌"); } phone.desc(); } }
1.2、传统方式实现的优缺点
-
优点:实现简单,代码易读。这也是博主小白刚入门能写出的代码,典型的面向过程编程。
-
缺点
-
违反开闭原则
即软件实体应当对扩展开放,对修改关闭。怎么理解呢?当厂家想新增vivo品牌手机的生产线时,这时候就需要在原来的基础上再添加一个
else if
分支来,本身修改代码并不是特别麻烦的事,麻烦的事是在我们需要修改所有订购手机的代码。 -
暴露实例细节
客户端可以清晰知道什么牌子的手机对应的实例实现,这样导致自己的内部细节暴露给了客户端。
-
2、简单工厂模式方案
知道了传统方式的弊端,那么解决方案也就好想了。我们也将创建手机实例的功能交给一个工厂类来执行,客户端只负责传递自己的需求,由工厂类来返回具体的手机实例。
2.1、代码实现
-
定义创建手机实例的工厂类,负责手机的生产
public class PhoneFactory { public static Phone newPhoneInstance(String phoneType) { //根据不同的类型创建不同的手机实例 if ("apple".equals(phoneType)) { return new ApplePhone(); } else if ("xiaomi".equals(phoneType)) { return new MiPhone(); } else if ("huawei".equals(phoneType)) { return new HwPhone(); } else { throw new RuntimeException("不支持的手机品牌"); } } }
-
那么客户端代码可以修改为
public static void main(String[] args) { String phoneType = "huawei"; //利用工厂类创建手机实例 Phone phone = PhoneFactory.newPhoneInstance(phoneType); phone.desc(); }
2.2、方案解析
根据上面的代码我们可以看到,我们定义了一个工厂类,客户端直接调用工厂类的静态方法获取手机实例,工厂类根据客户的传递参数返回具体的实现类。这样一方面对客户端隐藏了实现类细节,客户端只知道手机的接口,无法知道具体是哪一个实现类;另一方面所有生产手机都可以调用该处逻辑,后续如果添加手机品牌也只需要修改一处即可。
三、模式剖析
经过上次的案例分析,大家应该对简单工厂模式有个大概的认识,接下来我们从该模式本身进行全面剖析。
1、模式定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
2、模式结构
简单工厂模式一般包含如下角色
-
Factory
:工厂角色工厂角色负责实现创建所有实例的内部逻辑
-
Product
:抽象产品角色抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口(也可以是抽象类)
-
ConcreteProduct
:具体产品角色抽象产品角色的实现类
3、模式结构图
4、优缺点
- 优点
- 工厂类负责实例的创建细节,且对客户端隐藏,清晰划分责任,专门的类做专门的事。
- 一定程度上提高系统的灵活性,扩展性。扩展产品时主要添加产品实现类、修改工厂类逻辑,客户端无需修改,只需要修改传递参数即可完成。
- 缺点
- 由于工厂类负责了整个系统的产品创建,所以一旦工厂类出问题,会影响到整个系统。
- 每增加一个产品就会增加一个产品的实现类,一定程度上增加系统的复杂性。
- 工厂类的频繁修改。每次添加一个产品就需要修改工厂类。当产品数量过多时,会导致创建产品的逻辑过于复杂,不利于维护。
- 简单工厂模式一般使用静态工厂形式,造成工厂角色无法形成基于继承的等级结构。
5、使用场景
- 如果想要对客户端隐藏对象创建的细节,完全封装隔离具体的实现,可以考虑使用。
- 集中管理对象的创建(这些对象可以相关、也可以不相关)。目的实现集中管理和控制