《设计模式入门》 2.工厂方法模式
工厂方法模式(Factory Method Pattern)又称为工厂模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
简单来说就是我们不去直接生成对应的具体产品,而是把生产产品的功能交给工厂,我们只需要给工厂下订单就好了。
工厂方法模式一般分为四个部分:
抽象工厂(AbstractCreator)角色:担任这个角色的是工厂方法模式的核心,它是与应用程序无关的。任何在模式中创建对象的工厂类必须继承或者实现这个接口,在实际的系统中,这个角色常常有Java抽象类来实现。
具体工厂(ConcreteCreator)角色:担任这个角色的是实现了抽象工厂接口的具体Java类。具体工厂角色含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
抽象产品(AbstractProduct)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在实际应用中这个角色常常由Java的抽象类来实现。
具体产品(ConcreteProduct)角色:这个角色实现了抽象产品角色所声明的接口,工厂方法所创建的每一个对象都是某个具体产品角色的实例。
=========================================================================
还是生产手机的例子:
------------------------------------------------
假设我们有工厂生产手机,我们有三种手机,分别是华为P50,小米12,还有苹果Iphone13 Pro Max。
这时候我们来想,我们不直接去生产手机,而是把手机生产交给第三方代工厂,让他们来生产手机,这样我们只需要去对应相应的代工厂发订单,就可以生产相应的手机了,不需要知道代工厂的生产过程。
------------------------------------------------
抽象工厂角色:
对应工厂的父类,有创建手机的功能 。
package FactoryMethodPattern.factories;
import Phones.Phone;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Factory.java
* @Description 工厂的抽象类
* @createTime 2022年02月10日 16:51:00
*/
public abstract class Factory {
/**
*创建对应的手机
* @return 返回创建好对应的手机
*/
public abstract Phone createPhone();
}
具体工厂角色:
继承并且实现了具体的制造手机的方法,制造对应的手机 。
英华达代工小米
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Envada.java
* @Description 小米代工厂
* @createTime 2022年02月10日 16:59:00
*/
public class Envada extends Factory{
@Override
public Phone createPhone() {
return new XiaoMi11U();
}
}
伟创力代工华为
package FactoryMethodPattern.factories;
import Phones.HuaWeiP50;
import Phones.Phone;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Flex.java
* @Description 华为代工厂
* @createTime 2022年02月10日 17:00:00
*/
public class Flex extends Factory{
@Override
public Phone createPhone() {
return new HuaWeiP50();
}
}
富士康代工苹果
package FactoryMethodPattern.factories;
import Phones.IPhone13ProMax;
import Phones.Phone;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName FoxConn.java
* @Description IPHONE代工厂
* @createTime 2022年02月10日 16:57:00
*/
public class FoxConn extends Factory {
@Override
public Phone createPhone() {
return new IPhone13ProMax();
}
}
抽象产品角色 :
和简单工厂一样,对应代工产品的一个抽象
package Phones;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Phones.Phone.java
* @Description 手机抽象方类,所有抽象方法在子类进行实现
* @createTime 2022年02月08日 17:27:00
*/
public abstract class Phone {
/**
*打电话功能抽象方法
*/
public abstract void call();
/**
*短信功能抽象方法
*/
public abstract void message();
/**
*游戏功能抽象方法
*/
public abstract void game();
}
具体产品角色:
小米的实现类
package Phones;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName XiaoMi12.java
* @Description Mi11U的实现类
* @createTime 2022年02月08日 17:03:00
*/
public class XiaoMi11U extends Phone{
public XiaoMi11U(){
System.out.println("create XiaoMi11U");
}
@Override
public void call() {
System.out.println("da....da.....da....");
}
@Override
public void message() {
System.out.println("Message: Hello MIUI");
}
@Override
public void game() {
System.out.println("WIFI ERROR");
}
}
华为的实现类
package Phones;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName MiPhone.java
* @Description 华为的实现类
* @createTime 2022年02月08日 17:02:00
*/
public class HuaWeiP50 extends Phone{
public HuaWeiP50(){
System.out.println("create HuaWeiP50");
}
@Override
public void call() {
System.out.println("di...di....di....");
}
@Override
public void message() {
System.out.println("Message: Hello Harmony");
}
@Override
public void game() {
System.out.println("WeGame Start");
}
}
苹果的实现类
package Phones;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName IPhone.java
* @Description Iphone 的实现类
* @createTime 2022年02月08日 17:02:00
*/
public class IPhone13ProMax extends Phone {
public IPhone13ProMax(){
System.out.println("create iphone");
}
@Override
public void call() {
System.out.println("du....du....du....");
}
@Override
public void message() {
System.out.println("Imessage: Hello Iphone");
}
@Override
public void game() {
System.out.println("IGame Start");
}
}
主函数:
主函数下,我们不需要知道生产的过程和结果,我们需要做的只是给代工厂下订单,代工厂就可以制造对应的手机了
package FactoryMethodPattern;
import FactoryMethodPattern.factories.Envada;
import FactoryMethodPattern.factories.Factory;
import FactoryMethodPattern.factories.Flex;
import FactoryMethodPattern.factories.FoxConn;
import Phones.Phone;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName BuyPhone2.java
* @Description 通过代工厂进行创建
* @createTime 2022年02月10日 17:02:00
*/
public class BuyPhone2 {
public static void main(String[] args) throws Exception {
//输入代工厂
String type = "FoxConn";
Factory factory = getByFactory(type);
Phone phone = factory.createPhone();
phone.message();
}
public static Factory getByFactory(String type) throws Exception {
if (!type.isEmpty()) {
switch (type) {
case "FoxConn":
return new FoxConn();
case "Flex":
return new Flex();
case "Envada":
return new Envada();
default:
System.out.println("Create Error: Error Type");
throw new Exception();
}
} else {
System.out.println("Create Error: No Type Identify");
throw new Exception();
}
}
}
模式优点 :
在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
模式缺点 :
在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。