0.摘要
本文主要从下述5个方面来讲述工厂模式
- 简单工厂模式
- 工厂模式
- 抽象工厂模式
- 三种工厂模式的比较
- 反射对工厂模式的优化
1.简单工厂模式
理解:由一个工厂对象决定创建出哪一种产品类的实例。
分为三种组成元素
- 工厂类(Factory):进行逻辑判断;根据传入工厂类的入参不同,进行逻辑判断生成父类方法不同实现的产品对象,即返回一个父类对象,但这个父类是new的不同子类实现。
- 父类(Father):声明一个方法,可以是抽象类和接口,也可以是普通类,只要实现类/子类依据不同的需求具体实现/重写这个方法即可。
- 子类(Child):每个子对父类的抽象方法做不同的实现。
具体流程如下
1.1.工厂类
Factory类中有一个静态方法根据入参返回各种不同的父类实现(产品)。
public class Factory{
/**
* @param a 参数a 用来判断,决定生成哪种产品
* @return 生成产品
*/
public static Father createFather(String a) {
Father fa = null;
switch (a) {
case "产品一":
fa = new Child1();
break;
case "产品二":
fa = new Child2();
break;
}
// 此处省n种产品分支
return fa;
}
}
1.2.父类
Father类有一个方法,如果是抽象方法会被子类实现,如果不是抽象方法,会被子类重写;继承与实现中都是对此方法的不同实现,其实可以看作是一样的。
public abstract class Father {
public abstract void getResult();
}
1.3.子类
public class Child1 extends Father {
@Override
public void getResult() {
System.out.println("产品一");
}
}
public class Child2 extends Father {
@Override
public void getResult() {
System.out.println("产品二");
}
}
1.4.生成产品和增加产品
生成产品
// 步骤一
Father fa = Factory.createFather("产品一");
// 步骤二
fa.getResult();
增加产品
- 需要改变工厂类(加一个判断分支)
- 需要新建一个实现新功能的子类
1.5.优点与缺点
优点:
- 判断在工厂类中
- 根据传参可以动态生成不同是实现的类
- 解耦合
缺点: - 违反开闭原则中,面向更改关闭,新增产品时,必然会接触到工厂类代码
- 每次创建对象,都要通过工厂创建,即每次都要根据入参调用工厂类中的生成产品的方法。如果是新建n个一样的产品,也必须依照顺序创建。
2.工厂模式
理解:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟化其子类。
分为四种组成元素
- 工厂接口(IFactory):把工厂类抽象出一个接口,返回一个父类对象。
- 工厂类(Factory):工厂接口的各种实现类,每个工厂接口的实现类的方法返回的都是对应父类方法实现的一种产品。
- 父类(Father):声明一个方法,可以是抽象类和接口,也可以是普通类,只要实现类/子类依据不同的需求具体实现/重写这个方法即可。
- 子类(Child):每个子类对父类的抽象方法做不同的实现。
具体流程如下
2.1.工厂接口
public interface IFactory {
Father createFather();
}
2.2.工厂类
public class AFactory implements IFactory {
@Override
public Father createFather() {
Father fa = new AChild();
return fa;
}
}
public class BFactory implements IFactory {
@Override
public Father createFather() {
Father fa = new BChild();
return fa;
}
}
2.3.父类
public abstract class Father {
public abstract void getResult();
}
2.4.子类
public class AChild extends Father {
@Override
public void getResult() {
System.out.println("产品A");
}
}
public class BChild extends Father {
@Override
public void getResult() {
System.out.println("产品B");
}
}
2.5l生成产品和增加产品
生产产品
// 步骤一
IFactory factory= new Afactory();
// 步骤二
Father fa = factory.createFather;
// 步骤三
fa.getResult();
增加产品
- 需要增加一个工厂类。
- 需要新建一个实现新功能的子类。
2.6.优点和缺点
优点:
- 不违背开闭原则。
- 把判断逻辑从工厂中移到客户端中(具体使用是直接根据需要创建工厂类,根据工厂类创建实现不同接口的子类)。
3.抽象工厂模式
理解:他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
分为四种组成元素:
- 工厂接口:对应工厂类抽象出不止一个接口,返回多个父类对象(以前可能只返回一个电脑配置的处理器,后来发现还有内存、硬盘等)。
- 工厂类:工厂不同接口方法的不同实现,每个方法返回不同的产品。
- 父类:不只一个父类,每种工厂实现都对应着一种父类 。
- 子类:每种工厂的每钟产品的每个实现都有一个子类。
3.1.工厂接口
public interface IFactroy {
Cpu createCpu();
Memory createMemory();
}
3.2.工厂类
public class AFactory implements IFactroy {
@Override
public Cpu createCpu() {
Cpu cpu = new ACpu();
return cpu;
}
@Override
public Memory createMemory() {
Memory memory = new Amemory();
return memory;
}
}
public class BFactory implements IFactroy {
@Override
public Cpu createCpu() {
Cpu cpu = new BCpu();
return cpu;
}
@Override
public Memory createMemory() {
Memory memory = new Bmemory();
return memory;
}
}
3.3.父类
public abstract class Cpu {
public abstract void getKind();
}
public abstract class Memory {
public abstract void getSize();
}
3.4.子类
public class ACpu extends Cpu {
@Override
public void getKind() {
System.out.println("1070");
}
}
public class BCpu extends Cpu {
@Override
public void getKind() {
System.out.println("1060");
}
}
public class Amemory extends Memory {
@Override
public void getSize() {
System.out.println("16G");
}
}
public class Bmemory extends Memory {
@Override
public void getSize() {
System.out.println("32G");
}
}
3.5.生成产品和新增产品
生产产品
// 步骤一
IFactroy factory = new AFactory();
// 步骤二
factory.createCpu();
factory.createMemory();
新增产品与新增产品纬度
仅仅新增产品的话(以前只生产i3,i5的电脑,现在多加了i7),需要增加工厂,增加父类、子类。
增加产品纬度的话(以前生产电脑,现在还要配不同价位的电脑包),需要更改工厂接口,更改的工厂类,增加父类,增加子类。有可能还需要增加工厂类。
3.6.优点与缺点
优点:
可以在类的内部对产品族(想互有依靠关系的产品)进行约束,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
缺点:
产品族每新加一种产品都会有很多改变,工厂接口需要增加方法,需要增加新产品的的父抽象类或实现,增加各工厂类新产品接口方法的不同实现。
4.三种工厂模式比较
4.1.相同点与不同点
相同点
- 结构上讲,工厂类必不可少,本质属于建造者,工厂生成产品
- 共有优点,解耦和。
不同点
- 简单工厂模式生成何种产品的逻辑判断在工厂类里(通过传入的参数不同直接生成了产品),工厂模式与抽象工厂模式都是通过构造不同的工厂类,决定生成何种产品。这也是为什么简单工厂模式是只需要工厂类,而工厂模式与抽象工厂模式必须有工厂接口。
- 简单工厂模式没有遵循开闭原则中的面对更改闭合,工厂模式和抽象工厂模式遵循了开闭原则。
4.2.比较
不知道是出于(闭合性原则的)原因还是结果,导致了工厂模式与抽象工厂模式符合了闭和原则,抽象工厂模式又是因为多个不同维度的产品才对工厂模式进行了扩展(个人理解),
从大体上讲,可以分为两类,一类简单工厂模式、一类是工厂模式与抽象工厂模式
-
简单工厂模式简单粗暴,逻辑处理在工厂类,接口实现在子类,清清楚楚,除了风险(闭合原则),在不是多种维度产品时可以符合大多场景的使用,一个工厂产出不同需求产品。只是如果每次传参都不确定的话,工厂对象是需要反复构建的。
-
工厂模式对简单工厂模式,不能说一定好,他解决了(开闭原则)问题,消除了部分风险,但是他少了一灵活的判断,一个决定选用哪种工厂的判断,在工厂对象出现时,就已经确定了何种产品。这种方式的优点是在代码层面上是完全规避风险的,但是无法动态生成灵活工厂对象与相应的产品,之前的简单工厂模式靠传入参数(参数控制),现在靠写死工厂对象(之后我会说明反射如何解决这个难题的,前人智慧是真的强)。
-
抽象工厂模式中的抽象是抽象的是接口,新增维度产品时代码量是倍增的,但缺点只是代码量(如果还要说缺点的话,我个人觉得这种模式也不太符合开闭原则),不能说不如前两种模式,因为场景不一样,前两种工厂模式根本没有办法解决这种场景,当出现这种场景和需求时,你没有办法再依靠前两种工厂模式解决。那这就是他的优点,如果不需要的时候,不要强行用,合适的才是最好的,适用于很多设计模式。
5.0.反射对工厂模式的优化
这三种模式在代码使用时有一个公共的缺点,虽然表现形式不一样,简单工厂模式表现为需要switch/if判断,需要传参给工厂类,生成产品类,有点low,后两种虽然规避了传参这个问题,直接确定好了工厂类,但却不够灵活,如果修改产品,每次都要改代码。
我想可以控制生成规则,又想符合开闭原则,尽量不修改代码,能不能通过更改配置,变化入参,决定我想生成的产品,反射加配置文件成了最优的解决方案,甚至配置文件中的配置也以放在数据库里,对简单工厂模式来讲,可以通过反射去掉switch和if,对于工厂模式和抽象工厂模式,也可以通过反射构造具体的工厂。例如,很多框架都是通过配置文件(properties、xml)等来决定建立哪种数据库的连接,如果我配置的是mysql数据库,我只需要配置好mysql的包名和类名,反射就可以直接创建是mysql连接。IOC模式基本上就是靠反射初始化生成bean。