系列文章目录
前言
今天给大家介绍23种设计模式中的工厂模式,学过Spring的小伙伴应该不陌生,今天给大家详细介绍一下它。🌈
注意:文章若有错误的地方,欢迎评论区里面指正 🍭
1、工厂模式的分类
工厂模式可以分为三类:
2、什么是工厂模式
工厂模式 是一种创建型 设计模式,它提供了一种封装对象创建过程 的方式,使得代码更加灵活 、可维护 和可扩展。在工厂模式中,对象的创建不再由调用者直接负责,而是通过一个专门的工厂类来负责创建。这样,调用者就无需关心对象的创建细节,只需向工厂类请求所需的对象即可。
3、工厂模式的角色
- 产品(Product):定义了产品的接口或抽象类,描述了产品的主要功能和特性。
- 具体产品(Concrete Product):实现了产品接口或继承了产品抽象类的具体类,是工厂类创建的目标。
- 工厂(Factory):负责创建产品的工厂接口或抽象类,其中包含了创建产品的方法。
- 具体工厂(Concrete Factory):实现了工厂接口或继承了工厂抽象类的具体类,负责具体创建产品的实例。
4、工厂模式的优点在哪里
- 解耦:将对象的创建与使用分离,降低了代码之间的耦合度。
- 灵活性:可以很容易地创建不同的产品实例,只需修改工厂类的实现即可。
- 可扩展性:当需要添加新产品时,只需添加新的具体工厂和具体产品类,无需修改原有代码。
- 易于维护:将对象的创建封装在工厂类中,使得代码更加清晰和易于维护。
一、简单工厂模式
1、简单工厂模式的角色
简单工厂的角色如下:
|----------|----------------------------------------------------|
| 抽象产品 | 定义了产品的接口或抽象类,描述了产品的主要功能和特性。它是所有具体产品的基类,为它们提供了统一的接口 |
| 具体产品 | 实现了产品接口或继承了产品抽象类的具体类,是简单工厂模式创建的目标 |
| 简单工厂 | 负责创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。 |
2、简单工厂模式的示例
定义一个抽象的手机产品Phone:
java
public interface Phone {
void showBrand();
}
定义具体手机产品HuaWei 、ThreeStar 、Apple:
java
public class HuaWei implements Phone{
@Override
public void showBrand() {
System.out.println("这是一个华为手机。");
}
}
public class ThreeStar implements Phone{
@Override
public void showBrand() {
System.out.println("这是一个三星的手机。");
}
}
public class Apple implements Phone{
@Override
public void showBrand() {
System.out.println("这是一个苹果手机。");
}
}
定义手机工厂PhoneFactory:
java
public class PhoneFactory {
public static Phone showPhone(String brandName){
if ("HuaWei".equals(brandName)){
return new HuaWei();
}
if ("ThreeStar".equals(brandName)){
return new ThreeStar();
}
if ("Apple".equals(brandName)){
return new Apple();
}
return null;
}
}
测试:
java
public class PhoneTest {
public static void main(String[] args) {
Phone huaWei = PhoneFactory.showPhone("HuaWei");
if (null != huaWei) huaWei.showBrand();
else System.out.println("无法生成该品牌的手机。");
}
}
//测试结果:
/*
这是一个华为手机。
*/
在简单工厂模式中,抽象产品既可以是各个具体产品类实现的共同的接口,也可以是各个具体产品类继承的抽象父类。
3、简单工厂模式使用场景
创建对象不涉及复杂的逻辑:当创建对象时,不需要考虑太多的逻辑和条件判断,只是简单地根据传入的参数返回对应类型的实例时,可以使用简单工厂模式。
减少客户端代码对类的依赖:在客户端代码中,如果直接依赖于多个具体的类,会导致代码变得复杂且难以维护。使用简单工厂模式,客户端只需要依赖于工厂接口,从而降低了代码之间的耦合度。
需要动态地选择具体的类:在某些情况下,客户端可能需要根据运行时的情况动态地选择创建哪个类的实例。简单工厂模式可以根据传入的参数或条件来选择并创建相应的对象。
创建对象需要消耗较多资源:如果创建对象需要消耗较多的资源或执行复杂的初始化操作,使用简单工厂模式可以将这些操作封装在工厂类中,从而简化了客户端代码,并提高了代码的可读性和可维护性。
创建对象需要遵守一些约束或规则:在某些情况下,创建对象需要遵守一些约束或规则,例如,需要确保在单例模式下只创建一个实例,或者在创建对象前需要进行一些验证操作。简单工厂模式可以在工厂类中实现这些约束或规则,从而确保创建的对象符合预期的要求。
4、简单工厂模式总结
优点:
简单工厂模式通过把对象的创建过程封装在简单工厂类中,使得客户端与具体产品类解耦,提高了系统的灵活性和可扩展性
缺点:
当需要添加新产品时,需要修改简单工厂类的代码,这违反了开闭原则(对扩展开放,对修改关闭)
二、工厂方法模式
工厂方法模式:它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。
1、工厂方法模式的角色:
|----------|------------------------------------------------------------|
| 抽象产品 | 这是定义产品的接口,是工厂方法模式所创建的对象的超类型,也就是产品对象的公共父类。 |
| 具体产品 | 它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。 |
| 抽象工厂 | 在抽象工厂类中声明了工厂方法,用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。 |
| 具体工厂 | 它是抽象工厂的实现类,实现了在抽象工厂中声明的工厂方法,并可由客户端调用,返回一个具体产品类的实例。 |
2、工厂方法模式的示例
抽象工厂PhoneFactory:
java
public interface PhoneFactory {
Phone CreatePhone();
}
抽象产品Phone:
java
public interface Phone {
void showBrand();
}
具体产品工厂HuaWeiFactory、ThreeStarFactory、AppleFactory:
java
public class HuaWeiFactory implements PhoneFactory{
@Override
public Phone CreatePhone() {
System.out.println("这是华为手机工厂,这里只生产华为手机。");
return new HuaWei();
}
}
public class ThreeStarFactory implements PhoneFactory{
@Override
public Phone CreatePhone() {
System.out.println("这是三星手机工厂,这里只生产三星手机。");
return new ThreeStar();
}
}
public class AppleFactory implements PhoneFactory{
@Override
public Phone CreatePhone() {
System.out.println("这是苹果手机工厂,这里只生产苹果手机。");
return new Apple();
}
}
具体产品跟简单工厂的一样,还是HuaWei、ThreeStar、Apple那三个。
测试:
java
public class test {
public static void main(String[] args) {
HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
Phone phone = huaWeiFactory.CreatePhone();
phone.showBrand();
}
}
//测试结果:
/*
这是华为手机工厂,这里只生产华为手机。
这是一个华为手机。
*/
3、工厂方法模式使用场景
- 重复代码:当创建对象需要使用大量重复的代码时,工厂方法模式可以通过定义一个单独的创建实例对象的方法,来解决这个问题。
- 不关心创建过程:如果客户端不依赖产品类,不关心实例如何被创建、实现等细节,那么工厂方法模式是一个好选择。客户端只需要知道所对应的工厂,而具体的产品对象,由对应的工厂创建。
- 子类指定创建对象:当一个类希望由子类来指定它所创建的对象时,工厂方法模式也是一个不错的选择。
- 需要提供默认值和允许自定义值:如果一个类需要提供一些默认值,同时允许用户自定义这些值,工厂方法模式同样适用。
4、工厂方法模式总结
优点:
- 解耦:使用工厂方法可以让用户的代码和某个特定类的子类的代码解耦。
- 无需关心创建细节:用户不必知道它使用的对象是怎么样被创建的,只需知道该对象有哪些方法即可。
- 符合"开放-封闭"原则:工厂方法模式改变了我们直接用new创建对象的方式,使得在添加新产品时,只是扩展的变化,而不是修改的变化,这完全符合"开放-封闭"原则。
缺点:
- 增加类的数量:随着具体产品数量的增加,工厂类的数量也会增加,导致类的数量增多。
- 增加系统复杂度:由于需要定义多个工厂类,所以增加了系统的复杂度。对于系统的设计和维护都会带来很多困扰。
- 增加代码量:工厂方法模式需要定义抽象工厂类和抽象产品类,并且每个具体产品都需要一个对应的具体工厂类和具体产品类。这导致了代码的数量增加,增加了开发量和维护成本。
- 违背开闭原则:在添加新产品时,需要新增具体产品类和对应的具体工厂类。这违背了开闭原则,对于已有代码的修改会对系统稳定性造成一定的影响,需要进行大量的修改和测试。
- 运行效率低:由于工厂方法模式每次都需要通过具体工厂类来创建具体产品类的实例,这就需要实例化具体工厂类和具体产品类,可能导致运行效率较低。
三、抽象工厂模式
1、抽象工厂模式角色
|----------|----------------------------------------------------------------------------------|
| 抽象工厂 | 声明创建抽象产品对象的一个接口(有几个产品组,则声明几个方法。比如对于上述的场景,需要声明一个用于生产篮球类产品的方法,还需要声明一个用于生产足球类产品的方法) |
| 具体工厂 | 实现了抽象工厂接口,负责实例化具体产品类。每个具体工厂都对应一组相互关联或相互依赖的产品对象。 |
| 抽象产品 | 定义了产品的接口,是工厂方法所创建对象的超类型,或者是所创建对象的接口。 |
| 具体产品 | 实现了抽象产品接口,是某种类型的具体产品对象 |
2、抽象工厂模式示例
抽象工厂:
java
public interface AbstractFactory {
PhoneFactory CreateApplePhone();
BookFactory CreateBookPhone();
}
抽象产品:
java
public interface Book {
void showDetail();
}
public interface Phone {
void showDetail();
}
具体工厂:
java
//AppleFactory
public class AppleFactory implements AbstractFactory{
@Override
public PhoneFactory CreateApplePhone() {
return new Iphone15Phone();
}
@Override
public BookFactory CreateBookPhone() {
return new M3ProBook();
}
}
//AppleFactory
public class HuaWeiFactory implements AbstractFactory{
@Override
public Phone CreateApplePhone() {
return new HuaWeiP60Phone();
}
@Override
public Book CreateBookPhone() {
return new MateBookXProBook();
}
}
具体产品:
java
//Phone
public class HuaWeiP60Phone implements Phone {
@Override
public void showDetail() {
System.out.println("这是华为P60手机。");
}
}
public class Iphone15Phone implements Phone {
@Override
public void showDetail() {
System.out.println("这是苹果15手机。");
}
}
//Book
public class MateBookXProBook implements Book {
@Override
public void showDetail() {
System.out.println("这是华为MateBook X Pro笔记本。");
}
}
public class M3ProBook implements Book {
@Override
public void showDetail() {
System.out.println("这MacBook Pro M3 Pro笔记本电脑。");
}
}
测试:
java
public class client {
public static void main(String[] args) {
HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
huaWeiFactory.CreateApplePhone().showDetail();
huaWeiFactory.CreateBookPhone().showDetail();
System.out.println("===========================");
AppleFactory appleFactory = new AppleFactory();
appleFactory.CreateApplePhone().showDetail();
appleFactory.CreateBookPhone().showDetail();
}
}
/*
这是华为P60手机。
这是华为MateBook X Pro笔记本。
===========================
这是苹果15手机。
这MacBook Pro M3 Pro笔记本电脑。
*/
3、抽象工厂模式使用场景
- 系统独立于产品创建、组合和表示:当系统需要独立于它的产品的创建、组合和表示时,可以使用抽象工厂模式。
- 多个产品系列配置:如果系统需要由多个产品系列中的一个来配置,那么抽象工厂模式可以很好地满足这个需求。
- 强调产品对象联合使用:当需要强调一系列相关的产品对象的设计以便进行联合使用时,抽象工厂模式非常适用。
- 只想显示产品接口:如果只想提供一个产品类库,而只想显示它们的接口而不是实现时,抽象工厂模式是一个很好的选择。
4、抽象工厂模式总结
优点
封装性:抽象工厂模式将一组具有共同主题的单个工厂封装在一起,客户端只需要知道抽象工厂和产品族的抽象类型,而无需关心具体的实现细节。
产品族内的约束:抽象工厂模式有助于确保产品族内对象之间的兼容性。由于一个具体工厂负责创建一组产品,因此这组产品之间能够相互协作。
易于交换产品族:客户端代码只需与抽象工厂接口交互,因此可以轻松地更改产品族,而无需修改客户端代码。
可扩展性:当需要添加新的产品族时,只需添加新的具体工厂类,并在其中实现新的产品创建逻辑,而无需修改已有的代码。
降低耦合度:通过抽象工厂模式,客户端代码与具体产品类之间的耦合度被降低了,因为客户端代码只与抽象工厂接口交互。
缺点
难以支持新种类的产品:抽象工厂模式难以支持增加新的产品种类,因为每增加一个新的产品种类,就需要修改抽象工厂接口以及所有具体工厂类,这可能会违反开闭原则(对扩展开放,对修改关闭)。
系统复杂性增加:抽象工厂模式增加了系统的抽象性和复杂性,因为需要定义更多的接口和类。这可能会使得系统的理解和维护变得更加困难。
难以维护:如果产品族中的产品数量过多,或者产品之间的关联关系复杂,那么抽象工厂模式的实现和维护可能会变得非常困难。
客户端可能需要知道太多:在某些情况下,客户端可能需要知道抽象工厂的具体类型,以便能够创建正确的产品族。这可能会增加客户端代码的复杂性。
可能导致代码冗余:如果不同的产品族之间存在许多相似的产品,那么可能会导致在多个具体工厂类中出现相似的代码,从而产生代码冗余。
总结
好了,工厂模式就介绍到这里,我们下期见。