一、概念介绍
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种将对象创建的过程延迟到子类中进行的方法。这种模式通过定义一个创建对象的接口,但将具体的实现延迟到子类来完成,从而使得一个类在实例化时可以通过其子类来决定实例化哪个类。这样可以提高代码的灵活性和可扩展性。
工厂方法模式包含以下几个角色:
抽象产品(Abstract Product):定义了工厂方法模式所创建的对象的接口,通常是一个抽象类或接口。
具体产品(Concrete Product):实现了抽象产品接口,是工厂方法模式所创建的对象的具体实现类。
抽象工厂(Abstract Factory):定义了一个创建产品的工厂方法接口,通常是一个抽象类或接口。这个接口中通常会包含一个或多个工厂方法,用于创建具体产品的实例。
具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品的实例。
优点:
松耦合性:工厂方法模式将客户端与具体产品的实现分离,客户端只需知道产品的抽象类型,无需关心具体的实现细节,从而降低了客户端和具体产品之间的耦合性。
可扩展性:通过添加新的具体工厂和具体产品类,可以很方便地扩展系统的功能,而无需修改现有的代码。
符合开闭原则:对扩展开放、对修改关闭。增加新的产品类时,无需修改已有代码,只需添加新的具体产品类和具体工厂类即可。
缺点:
类的个数增加:引入了多个工厂类和产品类,使得系统中的类的数量增加,增加了代码的复杂度和维护成本。
增加了系统的抽象性和理解难度:工厂方法模式引入了更多的抽象层次,使得系统更加灵活,但也增加了理解和学习的难度。
工厂方法模式适用于以下情况:
当一个类不知道它所需要的对象的类时。
当一个类希望由它的子类来指定它所创建的对象时。
当类将创建对象的职责委托给多个帮助子类中的其中一个,并且想让子类中的某一个类来实例化这个类时。
二、实现方法(爷爷奶奶都看得懂~)
将以手机组装为例讲解工厂模式。中国的手机最具有性价比的手机是小米手机,美国最具性价比的手机是苹果手机,同一个工厂怎么生产小米手机和苹果手机呢?
1、简单工厂模式
生产前先出设计图,整体类图如下:
定义手机基类:
package designPattern.build.factory.simpleFactory.abstractProductClass;
/**
* 手机基类
*/
public abstract class BasicPhone {
/**价格级别*/
private String priceLevel;
/**品牌*/
private String brand;
/**手机会响铃*/
abstract String ring();
/**手机可以设置语言*/
abstract String language();
/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}
定义美国苹果手机(继承了手机基类):
package designPattern.build.factory.simpleFactory.abstractProductClass;
public class AmericanPhone extends BasicPhone {
public AmericanPhone() {
this.setPriceLevel("normal");
this.setBrand("Apple");
}
@Override
public String ring() {
return "DiDiDi";
}
@Override
public String language() {
return "English";
}
}
再定义中国小米手机(继承了手机基类):
package designPattern.build.factory.simpleFactory.abstractProductClass;
public class ChinesePhone extends BasicPhone {
public ChinesePhone() {
this.setPriceLevel("普通");
this.setBrand("小米");
}
@Override
public String ring() {
return "DuDuDu";
}
@Override
public String language() {
return "中文";
}
}
有了苹果手机和小米手机后,怎么用一个工厂生产出来呢?直接让一个工厂生产指定的手机即可,这个工厂只生产畅销手机,当销售地区为中国时就生产小米手机,当销售地区为美国时就生产苹果手机,
简单工厂如下:
package designPattern.build.factory.simpleFactory.abstractProductClass;
public class PhoneCreator {
public static BasicPhone producePhone(String nation) {
if ("中国".equals(nation)) {
return new ChinesePhone();
}
if ("美国".equals(nation)) {
return new AmericanPhone();
}
return null;
}
}
测试代码如下:
package designPattern.build.factory.simpleFactory.abstractProductClass;
/**
* 简单工厂模式
*/
public class Test {
public static void main(String[] args) {
// 生产一台中国销售的手机(小米手机)
BasicPhone phone1 = PhoneCreator.producePhone("中国");
// 生产一台美国销售的手机(苹果手机)
BasicPhone phone2 = PhoneCreator.producePhone("美国");
System.out.println("phone1的语言为:" + phone1.language() + ",响铃声音为:" + phone1.ring());
System.out.println("phone2的语言为:" + phone2.language() + ",响铃声音为:" + phone2.ring());
}
}
/**
输出如下:
phone1的语言为:中文,响铃声音为:DuDuDu
phone2的语言为:English,响铃声音为:DiDiDi
*/
观察以上的案例,如果后面要增加新手机型号生产,譬如要生产华为手机,需要修改PhoneCreator 的代码,很显然违背了对拓展开放,对修改关闭的原则。那要怎么办?
可以这样来,把生产手机的工厂抽象化,定义一种专门生产手机的基础工厂,各个地方要生产什么牌子的手机都行,只要继承基础工厂、然后进行具体实现即可!
下面的就是把工厂抽象一层的正常工厂模式。
2、普通工厂模式
我们的任务还是生产中国手机和美国手机。
设计前,先把设计类图整理好:
先定义手机基类:
package designPattern.build.factory.normalFactory;
/**
* 手机基类
*/
public abstract class BasicPhone {
/**价格等级*/
private String priceLevel;
/**品牌*/
private String brand;
/**销售地区*/
private String salesNation;
abstract String ring();
abstract String language();
public BasicPhone(String priceLevel, String brand, String salesNation) {
this.priceLevel = priceLevel;
this.brand = brand;
this.salesNation = salesNation;
}
/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}
美国手机:
package designPattern.build.factory.normalFactory;
/**
* 美国手机
*/
public class AmericanPhone extends BasicPhone {
public AmericanPhone(String priceLevel, String brand, String salesNation) {
super(priceLevel, brand, salesNation);
}
@Override
public String ring() {
return "DiDiDi";
}
@Override
public String language() {
return "English";
}
}
中国手机:
package designPattern.build.factory.normalFactory;
/**
* 中国手机
*/
public class ChinesePhone extends BasicPhone {
public ChinesePhone(String priceLevel, String brand, String produceDistrict) {
super(priceLevel, brand, produceDistrict);
}
@Override
public String ring() {
return "DuDuDu";
}
@Override
public String language() {
return "中文";
}
}
下面开始建工厂,首先定义手机工厂基类:
package designPattern.build.factory.normalFactory;
/**
* 抽象手机工厂
* 定义了生产手机的方法,可以看成只生产了无牌手机,具体贴啥牌可以由子工厂确定
* */
public interface BasicPhoneCreator {
BasicPhone producePhone(String salesNation);
}
再定义专门生产中国手机的工厂,只生产小米手机,实现了手机工厂基类:
注意,工厂模式下,每个具体工厂只能生产一种产品!
package designPattern.build.factory.normalFactory;
/**
* 中国手机生产厂:生产小米手机
*/
public class ChinaPhoneFactory implements BasicPhoneCreator {
@Override
public BasicPhone producePhone(String salesNation) {
return new ChinesePhone("低价", "小米", salesNation);
}
}
再定义美国手机生产厂,也实现了手机工厂基类:
注意,工厂模式下,每个具体工厂只能生产一种产品!
package designPattern.build.factory.normalFactory;
/**
* 美国手机生产厂:生产苹果手机
*/
public class AmericaPhoneFactory implements BasicPhoneCreator {
@Override
public BasicPhone producePhone(String salesNation) {
return new AmericanPhone("高价", "苹果", salesNation);
}
}
开始生产工作(测试代码):
package designPattern.build.factory.normalFactory;
/**
* 普通工厂模式
*/
public class Test {
public static void main(String[] args) {
// 中国有制造业优势,同样的造手机,中国价格更低
BasicPhoneCreator chinaFactory = new ChinaPhoneFactory();
BasicPhone phone1 = chinaFactory.producePhone("中国市场");
BasicPhone phone2 = chinaFactory.producePhone("美国市场");
BasicPhoneCreator americaFactory = new AmericaPhoneFactory();
BasicPhone phone3 = americaFactory.producePhone("中国市场");
BasicPhone phone4 = americaFactory.producePhone("美国市场");
System.out.println("中国工厂生产的phone1的销售市场为:" + phone1.getSalesNation() + ",默认品牌为:" + phone1.getBrand() + ",价格级别为:" + phone1.getPriceLevel());
System.out.println("中国工厂生产的phone2的销售市场为:" + phone2.getSalesNation() + ",默认品牌为:" + phone2.getBrand() + ",价格级别为:" + phone2.getPriceLevel());
System.out.println("美国工厂生产的phone3的销售市场为:" + phone3.getSalesNation() + ",默认品牌为:" + phone3.getBrand() + ",价格级别为:" + phone3.getPriceLevel());
System.out.println("美国工厂生产的phone4的销售市场为:" + phone4.getSalesNation() + ",默认品牌为:" + phone4.getBrand() + ",价格级别为:" + phone4.getPriceLevel());
}
}
/**
输出如下:
中国工厂生产的phone1的销售市场为:中国市场,默认品牌为:小米,价格级别为:低价
中国工厂生产的phone2的销售市场为:美国市场,默认品牌为:小米,价格级别为:低价
美国工厂生产的phone3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:高价
美国工厂生产的phone4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:高价
*/
通过以上案例我们发现,普通工厂只能生产一种牌子的手机,但是我们还想让工厂生产同一个牌子的其他周边物件就不行了,譬如专门生产苹果手机的工厂,我们还想让它同时生产苹果耳机;生产中国小米手机的工厂,我们还想让同时生成小米耳机。普通工厂实现不了,那怎么办?
我们只需要在工厂基类中增加方法即可!先前只能生产手机、现在加上周边设备的生产方法,如下:
3、抽象工厂模式
我们现在要求工厂不仅能生产手机、还要能生产同品牌的耳机。
开工前先画出设计类图:
先定义手机和耳机的类:
手机基类:
package designPattern.build.factory.abstractFactory;
/**
* 手机基类
* */
public abstract class BasicPhone {
/**价格等级*/
private String priceLevel;
/**品牌*/
private String brand;
/**销售国家*/
private String salesNation;
abstract String ring();
abstract String language();
public BasicPhone(String priceLevel, String brand, String salesNation) {
this.priceLevel = priceLevel;
this.brand = brand;
this.salesNation = salesNation;
}
/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}
中国手机(继承了手机基类):
package designPattern.build.factory.abstractFactory;
public class ChinesePhone extends BasicPhone {
public ChinesePhone(String priceLevel, String brand, String produceDistrict) {
super(priceLevel, brand, produceDistrict);
}
@Override
public String ring() {
return "DuDuDu";
}
@Override
public String language() {
return "中文";
}
}
美国手机(继承了手机基类):
package designPattern.build.factory.abstractFactory;
public class AmericanPhone extends BasicPhone {
public AmericanPhone(String priceLevel, String brand, String salesNation) {
super(priceLevel, brand, salesNation);
}
@Override
public String ring() {
return "DiDiDi";
}
@Override
public String language() {
return "English";
}
}
耳机基类:
package designPattern.build.factory.abstractFactory;
/**
* 耳机基类
* */
public abstract class BasicEarpieces {
/**价格级别*/
private String priceLevel;
/**品牌*/
private String brand;
/**销售国家*/
private String salesNation;
/**播放音乐的功能*/
abstract String playMusic();
public BasicEarpieces(String priceLevel, String brand, String salesNation) {
this.priceLevel = priceLevel;
this.brand = brand;
this.salesNation = salesNation;
}
/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}
中国耳机(继承了耳机基类):
package designPattern.build.factory.abstractFactory;
public class ChineseEarPieces extends BasicEarpieces {
public ChineseEarPieces(String priceLevel, String brand, String salesNation) {
super(priceLevel, brand, salesNation);
}
@Override
String playMusic() {
return "正在播放王菲的传奇:~~~~~~~~~~~~~~~~~~~~";
}
}
美国耳机(继承了耳机基类):
package designPattern.build.factory.abstractFactory;
public class AmericanEarPieces extends BasicEarpieces {
public AmericanEarPieces(String priceLevel, String brand, String salesNation) {
super(priceLevel, brand, salesNation);
}
@Override
String playMusic() {
return "正在播放Lady GaGa的BadRomance:~~~~~~~~~~~~~~~~~~~~";
}
}
重头戏来了,下面开始建厂,首先是工厂基类:
package designPattern.build.factory.abstractFactory;
/**
* 生产手机和手机周边设备的抽象工厂
* */
public interface BasicPhoneCreator {
/**生产手机*/
BasicPhone producePhone(String salesNation);
/**生产耳机*/
BasicEarpieces produceEarpieces(String salesNation);
}
中国手机工厂(实现了抽象工厂):生产小米手机、小米耳机,价格很实惠
package designPattern.build.factory.abstractFactory;
public class ChinesePhoneFactory implements BasicPhoneCreator {
@Override
public BasicPhone producePhone(String salesNation) {
return new ChinesePhone("3000元以内", "小米", salesNation);
}
@Override
public BasicEarpieces produceEarpieces(String salesNation) {
return new ChineseEarPieces("500元以内", "小米", salesNation);
}
}
美国手机工厂(实现了抽象工厂):生产苹果手机、苹果耳机,价格很昂贵
package designPattern.build.factory.abstractFactory;
public class AmericanPhoneFactory implements BasicPhoneCreator {
@Override
public BasicPhone producePhone(String salesNation) {
return new AmericanPhone("8000元以上", "苹果", salesNation);
}
@Override
public BasicEarpieces produceEarpieces(String salesNation) {
return new AmericanEarPieces("2000元内", "苹果", salesNation);
}
}
产品已经定义好、工厂也建立好,下面开始生产(测试代码):
package designPattern.build.factory.abstractFactory;
/**
* 抽象工厂模式
*/
public class Test {
public static void main(String[] args) {
// 中国有制造业优势,同样的造手机,中国价格更低
/**
* AmericaPhoneFactory和ChinaPhoneFactory中的producePhone方法的实现似乎混淆了工厂方法模式的意图。通常,一个工厂类负责生产一种产品。
* 但在你的案例中,每个工厂似乎都能生产多种产品。这种实现更接近于简单工厂模式,而不是工厂方法模式。
* 工厂方法模式的关键在于有多个工厂类,每个工厂类负责创建一种具体的产品。但在你的逻辑中,一个工厂能够创建不同的产品,这与工厂方法模式的定义稍有出入。
* 总结
* 虽然你的实现基本遵循了工厂方法模式的构思,但对于工厂类的设计应该有更明确的职责划分,即一个工厂类负责创建一种类型的产品。你可能需要重新审视
* 每个工厂类的职责,确保它们遵守工厂方法模式的原则。
* */
// 生产手机
BasicPhoneCreator chinaFactory = new ChinesePhoneFactory();
BasicPhone phone1 = chinaFactory.producePhone("中国市场");
BasicPhone phone2 = chinaFactory.producePhone("美国市场");
BasicPhoneCreator americaFactory = new AmericanPhoneFactory();
BasicPhone phone3 = americaFactory.producePhone("中国市场");
BasicPhone phone4 = americaFactory.producePhone("美国市场");
System.out.println("中国工厂生产的手机phone1的销售市场为:" + phone1.getSalesNation() + ",默认品牌为:" + phone1.getBrand() + ",价格级别为:" + phone1.getPriceLevel());
System.out.println("中国工厂生产的手机phone2的销售市场为:" + phone2.getSalesNation() + ",默认品牌为:" + phone2.getBrand() + ",价格级别为:" + phone2.getPriceLevel());
System.out.println("美国工厂生产的手机phone3的销售市场为:" + phone3.getSalesNation() + ",默认品牌为:" + phone3.getBrand() + ",价格级别为:" + phone3.getPriceLevel());
System.out.println("美国工厂生产的手机phone4的销售市场为:" + phone4.getSalesNation() + ",默认品牌为:" + phone4.getBrand() + ",价格级别为:" + phone4.getPriceLevel());
// 生产耳机
BasicEarpieces earpieces1 = chinaFactory.produceEarpieces("中国市场");
BasicEarpieces earpieces2 = chinaFactory.produceEarpieces("美国市场");
BasicEarpieces earpieces3 = americaFactory.produceEarpieces("中国市场");
BasicEarpieces earpieces4 = americaFactory.produceEarpieces("美国市场");
System.out.println("中国工厂生产的耳机earpieces1的销售市场为:" + earpieces1.getSalesNation() + ",默认品牌为:" + earpieces1.getBrand() + ",价格级别为:" + earpieces1.getPriceLevel());
System.out.println("中国工厂生产的耳机earpieces2的销售市场为:" + earpieces2.getSalesNation() + ",默认品牌为:" + earpieces2.getBrand() + ",价格级别为:" + earpieces2.getPriceLevel());
System.out.println("美国工厂生产的耳机earpieces3的销售市场为:" + earpieces3.getSalesNation() + ",默认品牌为:" + earpieces3.getBrand() + ",价格级别为:" + earpieces3.getPriceLevel());
System.out.println("美国工厂生产的耳机earpieces4的销售市场为:" + earpieces4.getSalesNation() + ",默认品牌为:" + earpieces4.getBrand() + ",价格级别为:" + earpieces4.getPriceLevel());
}
}
/**
输出如下:
中国工厂生产的手机phone1的销售市场为:中国市场,默认品牌为:小米,价格级别为:3000元以内
中国工厂生产的手机phone2的销售市场为:美国市场,默认品牌为:小米,价格级别为:3000元以内
美国工厂生产的手机phone3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:8000元以上
美国工厂生产的手机phone4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:8000元以上
中国工厂生产的耳机earpieces1的销售市场为:中国市场,默认品牌为:小米,价格级别为:500元以内
中国工厂生产的耳机earpieces2的销售市场为:美国市场,默认品牌为:小米,价格级别为:500元以内
美国工厂生产的耳机earpieces3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:2000元内
美国工厂生产的耳机earpieces4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:2000元内
*/
三、总结
模式 | 特点 | 优点 | 缺点 |
---|---|---|---|
简单工厂模式(Simple Factory Pattern) | 工厂类负责创建所有对象的实例,客户端通过传递参数来获取对象 | 1. 客户端代码与实际创建对象的代码解耦 2. 简单易用 | 1. 工厂类承担所有对象创建职责,违背单一职责原则 2. 增加新产品时需要修改工厂类,违反开闭原则 |
普通工厂模式(Factory Method Pattern) | 定义创建对象的接口,由子类决定实例化哪一个类 | 1. 遵循开闭原则,增加新产品时只需增加相应的子类 2. 客户端代码与具体产品实现解耦 | 1. 增加系统复杂性,可能导致类数量增加 |
抽象工厂模式(Abstract Factory Pattern) | 提供一个创建相关或依赖对象家族的接口,无需指定具体的类 | 1. 易于交换产品系列,修改具体工厂类只需在一个地方进行 2. 保证客户端始终使用同一个产品系列 | 1. 增加系统的抽象层次和复杂性 |