设计模式之工厂方法和抽象工厂

简介: 全网最详细的工厂设计模式,本文主要是创建型设计模式中的工厂方法和抽象工厂,先由传统实现方式引出问题,接着对代码改进到简单工厂,后扩展到工厂方法,最后是抽象工厂模式,文中包括概念理解和相关实现代码。

设计模式之工厂方法和抽象工厂


全网最详细的工厂设计模式,本文主要是创建型设计模式中的工厂方法和抽象工厂,先由传统实现方式引出问题,接着对代码改进到简单工厂,后扩展到工厂方法,最后是抽象工厂模式,文中包括概念理解和相关实现代码。


一、引出问题


如果有一个客户老王,需要购买产品,产品分别是A、B、C。

如果用传统方法实现,分别定义A、B、C三个类,再分别创建他们所属的方法。

在客户对象中再分别调用他们的方法。

Product ClientProduct(String orderType) {
    Product product;
    if (orderType.equals("A")) {
        product = new ProductA();
    } else if (orderType.equals("B")) {
        product = new ProductB();
    } else if (orderType.equals("B")) {
        product = new ProductC();
    }
    // product制作过程
    product.common();
    return product;
}


如果我们需要再增加一个产品D,就需要判断再增加一个分支,然后在分支里面创建产品对象,调用产品D的方法。


这样代码的维护性是极差的,查看我们的软件设计七大原则,很明显,这违反了开闭原则、依赖倒置原则.

如果又有个客户小王,那么小王也必须依赖每个产品类,这样就显得冗杂。


二、简单工厂(静态工厂)

简单工厂(静态工厂)模式就应用而生了。

如果我们将产品A、B、C抽象出来一个父类,再专门创建一个工厂类,在客户购买产品时,只需要传入产品的类型,由工厂去创建产品。

简单工厂模式中包含如下角色:

Factory:工厂角色

工厂角色负责实现创建所有实例的内部逻辑。

Product:抽象产品角色

抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口。

ConcreteProduct:具体产品角色

具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

看看我们对原始实现方式后的代码。


产品抽象父类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Product {
    public void common(){
        System.out.println("这是产品父类公共方法...");
    }
}


产品A:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductA extends Product{
    public void common(){
        System.out.println("这是产品A方法...");
    }
}


产品B:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ProductB extends Product{
    public void common(){
        System.out.println("这是产品B方法...");
    }
}


工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class SimpleFactory {
    public Product createProduct(String orderType) {
        Product product = null;
        if (orderType.equals("A")) {
            product = new ProductA();
        } else if (orderType.equals("B")) {
            product = new ProductB();
        } else if (orderType.equals("C")) {
            product = new ProductC();
        }
        return product;
    }
}


客户老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {
    SimpleFactory simpleFactory;
    public Client(SimpleFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }
    public Product orderProduct(String orderType) {
        Product product;    
        product = simpleFactory.createProduct(orderType);
       //调用每个产出相应的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }
    public static void main(String[] args) {
        Client client=new Client(new SimpleFactory());
        client.orderProduct("A");
    }
}


这样简单工厂模式就实现了,这样的话老王和具体的产品就很好的解耦了,也不需要老王再依赖具体产品类,依赖倒置问题就很好的解决了。


如果增加一个产品D,需要再重新定义一个D类,实现product接口,而后在工厂类中增加一个分支结构。


显而易见这样实现,缺陷依然存在:

1、工厂类集中了所有产品创建逻辑,职责过重,一旦发生异常,整个系统将受影响。

2、使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。

3、系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。

4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

这种方法只是一种编码方式,并不输入设计模式的一种,且局限于产品种类较少。


三、工厂方法


在简单工厂中老王需要具体的产品,就在他自己的类中去创建需要的产品,老王虽然不依赖具体产品,但老王现在需要依赖工厂实现类了。

简单工厂是将产品类抽象化,具体的产品由工厂类去实现。

如果我们将工厂类也抽象化,那就引出了我们今天第一个设计模式——工厂方法。

工厂方法有四个角色:

1、抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 createProduct() 来创建产品。

2、具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

3、抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。

4、具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。


我们对简单工厂代码进行改造。

抽象产品父类、产品A类、产品B类保持不变。重点看工厂类


抽象工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class AbstractFactory {
    public abstract Product createProduct(String orderType);
}


具体实现工厂A类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryA extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {
        System.out.println("参数为:"+orderType);
        return new ProductA();
    }
}


具体实现工厂B类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreteFactoryB extends AbstractFactory{
    @Override
    public Product createProduct(String orderType) {
        return new ProductB();
    }
}


老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {
    AbstractFactory simpleFactory;
    public Client(AbstractFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }
    public Product orderProduct(String orderType) {
        Product product;
        product = simpleFactory.createProduct(orderType);
       //调用每个产出相应的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }
    public static void main(String[] args) {
        Client client=new Client(new ConcreteFactoryA());
        client.orderProduct("A");
    }
}


这样的好处就在于老王只管他要关注的抽象工厂,具体是哪个工厂实现类生产产品,老王也不需要关注。


典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。


缺点也是显而易见的:

类的个数容易过多,增加复杂度。

考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。

抽象产品只能生产一种产品。


如果对工厂方法依然一知半解的话,接着往下看工厂方法的一个典型实现

在JDK中对工厂方法有大量的运用,其中比较典型的是

new ArrayList<>().iterator();


我们知道集合的一个大分支依赖的是Collection接口,我们以ArrayList作为举例。

Collection接口相当于产品的抽象父类,ArrayList相当于具体产品。

Iterator是一个抽象工厂,在ArrayList中有一个Itr内部类实现了Iterator接口

当我们调用集合的iterator()方法遍历对象时,就会调用各自类的具体实现方法。


四、抽象工厂


有一天,产品A、B、C升级改造了,三种产品分别有红色和蓝色,如果还用工厂方法的话,那简直是个灾难,具体工厂实现类需要六个。

就引出我们今天的第二个设计模式——抽象工厂。


抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建创建一系列相关或相互依赖对象的家族,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。


抽象工厂模式与工厂方法模式区别在于,工厂方法模式针对的是一个产品等级结构。

而抽象工厂模式则需要面对多个产品等级结构(各种颜色),一个工厂等级结构可以负责多个不同产品等级结构(不同颜色)中的产品对象的创建 。


抽象工厂依然是四个角色:

AbstractFactory:抽象工厂

ConcreteFactory:具体工厂

AbstractProduct:抽象产品

Product:具体产品

我们开始改造工厂方法代码,既然是要把产品都分成一组,那理应把产品A、B、C都抽象出来,再让工厂类去实现各个产品的不同颜色,也就是概念中的——用于创建创建一系列相关或相互依赖对象的家族。

接口看改造后的代码:


产品抽象类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public interface Product {
    public void common();
}

产品抽象A家族类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductA implements Product {
    public abstract void common();
}


产品抽象B家族类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public abstract class ProductB implements Product {
    public abstract void common();
}


具体红色产品A类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class RedProductA extends ProductA{
    @Override
    public void common() {
        System.out.println("这是红色的产品A");
    }
}


具体蓝色产品A类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class BlueProductA extends ProductA {
    @Override
    public void common() {
        System.out.println("这是蓝色的产品A");
    }
}


抽象A家族工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public interface AbstractProductFactory {
    public ProductA createProduct(String orderType);
}


实现A家族工厂类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class ConcreateProductAFactory implements AbstractProductFactory{
    @Override
    public ProductA createProduct(String orderType) {
        return new BlueProductA();
    }
}


老王类:

/**
 * @author tcy
 * @Date 28-07-2022
 */
public class Client {
    ConcreateProductAFactory simpleFactory;
    public Client(ConcreateProductAFactory simpleFactory) {
        this.simpleFactory = simpleFactory;
    }
    public ProductA orderProduct(String orderType) {
        ProductA product;
        product = simpleFactory.createProduct(orderType);
       //调用每个产出相应的方法
        product.common();
        System.out.println(product.getClass());
        return product;
    }
    public static void main(String[] args) {
        Client client=new Client(new ConcreateProductAFactory());
        client.orderProduct("A");
    }
}


这样的话,每天工厂类可以把A的产品家族类(红、蓝)都实现,抽象工厂模式隔离了具体类的生成,使得老王并不需要知道什么产品被创建,从具体的产品解耦出来。

当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。


如果要增加新产品、和新工厂很容易,如果再增加一个等级(颜色)代码修改起来就很痛苦了。


抽象工厂模式在Spring中有大量的运用。

比较典型的是,BeanFactory 是用于管理 Bean 的一个工厂,所有工厂都是 BeanFactory 的子类。这样我们可以通过 IOC 容器来管理访问 Bean,根据不同的策略调用 getBean() 方法,从而获得具体对象。


BeanFactory 的子类主要有

ClassPathXmlApplicationContext、

XmlWebApplicationContext、

StaticWebApplicationContext、

StaticApplicationContext。

在 Spring 中,DefaultListableBeanFactory 实现了所有工厂的公共逻辑。


相关文章
|
17天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
2月前
|
设计模式 Java
Java设计模式-工厂方法模式(4)
Java设计模式-工厂方法模式(4)
|
3月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
3月前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
|
4月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
42 3
|
5月前
|
设计模式 Java
Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)
Java设计模式:工厂模式之简单工厂、工厂方法、抽象工厂(三)
|
5月前
|
设计模式 搜索推荐
工厂方法模式-大话设计模式
工厂方法模式-大话设计模式
|
5月前
|
设计模式 新零售 Java
设计模式最佳套路5 —— 愉快地使用工厂方法模式
工厂模式一般配合策略模式一起使用,当系统中有多种产品(策略),且每种产品有多个实例时,此时适合使用工厂模式:每种产品对应的工厂提供该产品不同实例的创建功能,从而避免调用方和产品创建逻辑的耦合,完美符合迪米特法则(最少知道原则)。
79 6
|
5月前
|
设计模式 Java
设计模式-抽象工厂(JAVA)
设计模式-抽象工厂(JAVA)

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78