您现在的位置是:首页 >技术杂谈 >创建型设计模式02-工厂方法模式网站首页技术杂谈

创建型设计模式02-工厂方法模式

猫十二懿 2024-07-01 11:59:37
简介创建型设计模式02-工厂方法模式

✨作者:猫十二懿

❤️‍?账号:CSDN掘金个人博客Github

?公众号:猫十二懿

工厂方法模式

1、工厂方法模式介绍

工厂方法模式(Factory Method Pattern)是一种常用的对象创建型设计模式,也被称为工厂模式、多态工厂模式和虚拟构造器模式等。该模式通过定义一个抽象工厂接口来创建一系列相关或者相互依赖的对象,而无需指定它们具体的类。

在工厂方法模式中,创建对象的操作延迟到工厂类的子类中去完成,即由子类来决定应该实例化哪一个具体产品类。这样就可以将客户端代码与具体类的实现分离开来,从而降低了客户端与具体类之间的耦合度,同时也有利于系统的扩展和升级。

image-20230418233750530

2、工厂方法模式举例

一个具体的例子是,假设我们正在开发一个电商平台,这个平台中有不同种类的商品需要进行销售。我们可以使用工厂方法模式来创建这些商品的实例。

首先,我们需要定义一个抽象的 Product 接口,这个接口包含了所有商品应该具备的共同属性和行为,比如获取商品名称、获取商品价格等。然后,我们可以针对不同类型的商品,创建具体的产品类,比如 BookProduct、ElectronicProduct 等,这些类都实现了 Product 接口并且具有自己特定的属性和行为。

接下来,我们需要定义一个 ProductFactory 工厂接口,其定义了一个创建产品的通用接口方法 createProduct()。然后针对不同类型的产品,分别创建具体的工厂类,比如 BookProductFactory、ElectronicProductFactory 等,每个工厂类分别实现了创建具体商品实例的方法。比如,BookProductFactory 实现了 createProduct() 方法用于创建具体的书籍商品实例。

  1. Product 接口,包含了所有商品应该具备的共同属性和行为:

    /**
     * @author Shier
     * 产品接口
     */
    public interface Product {
        // 产品共有的名称
        String getName();
    
        // 产品都有价格    
        double getPrice();
        
         // 买的是什么产品
        void productShow();
    }
    
  2. 定义两个具体的产品类 BookProduct 和 ElectronicProduct,实现 Product 接口并且具有自己特定的属性和方法:

    /**
     * @author Shier
     * 书本产品类
     */
    public class BookProduct implements Product {
        private String name;
        private double price;
    
        public BookProduct(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public double getPrice() {
            return this.price;
        }
        
        @Override
        public void productShow() {
            System.out.println("BookProduct{" +
                    "name='" + name + ''' +
                    ", price=" + price +
                    '}');
        }
    }
    
    /**
     * @author Shier
     *
     * 电子产品类
     */
    public class ElectronicProduct implements Product {
        private String name;
        private double price;
    
        public ElectronicProduct(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public double getPrice() {
            return this.price;
        }
        
        @Override
        public void productShow() {
            System.out.println("ElectronicProduct{" +
                    "name='" + name + ''' +
                    ", price=" + price +
                    '}');
        }
    }
    
  3. 定义一个 ProductFactory 工厂接口,其定义了一个创建产品的通用接口方法 createProduct():

    /**
     * @author Shier
     * 产品工厂接口
     */
    public interface ProductFactory {
        Product createProduct();
    }
    
  4. 然后针对不同类型的产品,分别创建具体的工厂类,比如 BookProductFactory、ElectronicProductFactory

    /**
     * @author Shier 
     * 书本工厂
     */
    public class BookProductFactory implements ProductFactory {
        private String name;
        private double price;
    
        public BookProductFactory(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public Product createProduct() {
            return new BookProduct(this.name, this.price);
        }
    }
    
    /**
     * @author Shier 
     * 电子产品工厂
     */
    public class ElectronicProductFactory implements ProductFactory {
        private String name;
        private double price;
    
        public ElectronicProductFactory(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public Product createProduct() {
            return new ElectronicProduct(this.name, this.price);
        }
    }
    
  5. 在客户端中,我们可以通过调用不同的具体工厂类的 createProduct() 方法,来创建具体类型的商品实例

    public class Client {
        public static void main(String[] args) {
            ProductFactory bookFactory = new BookProductFactory("Java编程思想", 99.9);
            Product book = bookFactory.createProduct();
            book.productShow();
    
            ProductFactory electronicFactory = new ElectronicProductFactory("iPad Pro", 7999);
            Product electronic = electronicFactory.createProduct();
            electronic.productShow();
        }
    }
    

最后输出的结果如下:

image-20230418223313188

这个模式可以将对象的创建和使用分离开来,并且能够提供更高级别的灵活性。当需要创建一组相关的对象时,工厂方法模式通常是非常有用的。例如,一个汽车制造厂可以使用工厂方法来根据不同的需求生产出不同类型的汽车,比如轿车、卡车或者SUV等。

每个具体实现类,都要去新建一个对应工厂类,就是将具体的实现延迟到子类当中进行实现了

4、 实现商场收银系统再次升级

简单工厂+策略+装饰+工厂方法实现

image-20230418233822084

主要的修改如下:

  1. 增加一个接口:

    /**
     * @author Shier
     * CreateTime 2023/4/18 23:02
     */
    public interface IFactory {
        public ISale createSalesModel(); // 共同都有的是销售模式
    }
    
  2. 先打折在满减先满减再打折、创建成一个工厂类,去实现上面这个接口,

    /**
     * @author Shier
     * CreateTime 2023/4/18 23:05
     * 先打折再满减类
     */
    public class CashRebateReturnFactory implements IFactory {
        
        private double moneyRebate = 1d;
        private double moneyCondition = 0d;
        private double moneyReturn = 0d;
    
        public CashRebateReturnFactory(double moneyRebate,double moneyCondition,double moneyReturn){
          this.moneyRebate=moneyRebate;
          this.moneyCondition=moneyCondition;
          this.moneyReturn=moneyReturn;
        }
    
        //先打x折,再满m返n
        public ISale createSalesModel(){
            
            CashNormal cn = new CashNormal();
            CashReturn cr1 = new CashReturn(this.moneyCondition,this.moneyReturn); 
            CashRebate cr2 = new CashRebate(this.moneyRebate);
            
            cr1.decorate(cn);   //用满m返n算法包装基本的原价算法
            cr2.decorate(cr1);  //打x折算法装饰满m返n算法
            return cr2;         //将包装好的算法组合返回
        }    
    }
    
    /**
     * @author Shier
     * CreateTime 2023/4/18 23:05
     * 先满减再打折类
     */
    public class CashReturnRebateFactory implements IFactory {
    
        private double moneyRebate = 1d;
        private double moneyCondition = 0d;
        private double moneyReturn = 0d;
    
        public CashReturnRebateFactory(double moneyRebate, double moneyCondition, double moneyReturn) {
            this.moneyRebate = moneyRebate;
            this.moneyCondition = moneyCondition;
            this.moneyReturn = moneyReturn;
        }
    
        //先满m返n,再打x折
        public ISale createSalesModel() {
    
            CashNormal cn2 = new CashNormal();
            CashRebate cr3 = new CashRebate(this.moneyRebate);
            CashReturn cr4 = new CashReturn(this.moneyCondition, this.moneyReturn);
    
            cr3.decorate(cn2);  //用打x折算法包装基本的原价算法
            cr4.decorate(cr3);  //满m返n算法装饰打x折算法
            return cr4;         //将包装好的算法组合返回
        }
    }
    
  3. 修改CashContext类,直接就使用上面定义好的这两个销售模式类,实现了松耦合的目的

    /**
     * @author Shier
     * CreateTime 2023/4/11 22:55
     */
    public class CashContext {
        /**
         * CashSuper对象
         */
        private ISale cashSuper;
    
        /**
         * 通过构造方法,传入具体的收费策略
         */
        public CashContext(int cashType) {
            //根据用户输入,将对应的策略对象作为参数传入CashContent对象中
            IFactory fs = null;
            switch (cashType) {
                case 1:
                    //原价
                    fs = new CashRebateReturnFactory(1d,0d,0d);
                    break;
                case 2:
                    //打8折
                    fs = new CashRebateReturnFactory(0.8d,0d,0d);
                    break;
                case 3:
                    //打7折
                    fs = new CashRebateReturnFactory(0.7d,0d,0d);
                    break;
                case 4:
                    //满300返100
                    fs = new CashRebateReturnFactory(1,300d,100d);
                    break;
                case 5:
                    //先打8折,再满300返100
                    fs = new CashRebateReturnFactory(0.8d,300d,100d);
                    break;
                case 6:
                    //先满200返50,再打7折
                    fs = new CashReturnRebateFactory(0.7d,200d,50d);
                    break;
                default:
                    break;
            }
            this.cashSuper = fs.createSalesModel();
        }
        /**
         * 根据不同的收费策略返回不同的结构
         */
        public double getResult(double price, int num) {
            return cashSuper.acceptCash(price, num);
        }
    }
    

最后的输出结果:

image-20230418233722368

从中可以发现,工厂方法模式不但做到了简单工厂违背的开闭原则的缺点,还保持了封装对象过程的优点。

5、总结

工厂方法模式包含四个角色:

  1. 抽象产品:所创建对象的父类或接口
  2. 具体产品:创建目标
  3. 抽象工厂:抽象产品的创建工厂
  4. 具体工厂:用于创建具体产品的工厂

工厂方法模式能够满足多种复杂对象的创建需求,并提供了一种灵活的解决方案,可以更好地符合设计原则中的开放封闭原则

优点:

  1. 增强了代码的可扩展性
  2. 降低了耦合度,解耦能力好
  3. 提高了代码的重复使用率
  4. 动态地创建对象
  5. 对于复制的参数的构造对象,可以很好对外层屏蔽代码的复杂性

缺点

  1. 会导致系统中类的个数增加、增加复杂度
  2. 使用时需要先创建工厂对象
  3. 带来额外的开销
  4. 增加了系统的抽象性和理解难度。

应用场景:

  1. 创建对象需要大量重复的代码
  2. 客户端(应用层)不依赖产品类实例如何被创建、如何被实现等细节
  3. 一个类通过其子类来指定创建哪个对象

工厂方法就是简单工厂模式的一个升级版本

的创建工厂
4. 具体工厂:用于创建具体产品的工厂

工厂方法模式能够满足多种复杂对象的创建需求,并提供了一种灵活的解决方案,可以更好地符合设计原则中的开放封闭原则

优点:

  1. 增强了代码的可扩展性
  2. 降低了耦合度,解耦能力好
  3. 提高了代码的重复使用率
  4. 动态地创建对象
  5. 对于复制的参数的构造对象,可以很好对外层屏蔽代码的复杂性

缺点

  1. 会导致系统中类的个数增加、增加复杂度
  2. 使用时需要先创建工厂对象
  3. 带来额外的开销
  4. 增加了系统的抽象性和理解难度。

应用场景:

  1. 创建对象需要大量重复的代码
  2. 客户端(应用层)不依赖产品类实例如何被创建、如何被实现等细节
  3. 一个类通过其子类来指定创建哪个对象

工厂方法就是简单工厂模式的一个升级版本

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。