• 【设计模式】2.工厂模式


    1. 工厂模式概述

    工厂模式属于创建型模式的一种。

    在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则

    工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,使得如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦

    开闭原则:

    开闭原则要求对 扩展开放(对提供方),对修改关闭(对使用方)

    工厂模式分为以下三种:

    • 简单工厂模式(不属于GOF的23种经典设计模式)
    • 工厂方法模式
    • 抽象工厂模式

    2. 简单工厂模式

    简单工厂不是一种设计模式,反而比较像是一种编程习惯

    简单工厂模式的核心是定义一个创建对象的接口将对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。

    简单工厂包含如下角色:

    • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品 :实现或者继承抽象产品的子类
    • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。

    实现简单工厂模式的基本思路是什么?

    简单工厂的实现思路是,定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。简单工厂适用于需要创建的对象较少或客户端不关心对象的创建过程的情况

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VKO6QEBf-1668690825240)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/9944/%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.png)]

    工厂类代码如下:

    public class SimpleCoffeeFactory {
    
        public Coffee createCoffee(String type) {
            Coffee coffee = null;
            if("americano".equals(type)) {
                coffee = new AmericanoCoffee();
            } else if("latte".equals(type)) {
                coffee = new LatteCoffee();
            }
            return coffee;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    咖啡店类

    public class CoffeeStore {
    
        public Coffee orderCoffee(String type) {
    
            SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
            //调用生产咖啡的方法
            Coffee coffee = factory.createCoffee(type);
    
            //加配料
            coffee.addMilk();
            coffee.addsugar();
    
            return coffee;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类

    public class Client {
        public static void main(String[] args) {
            //创建咖啡店类对象
            CoffeeStore store = new CoffeeStore();
            Coffee coffee = store.orderCoffee("latte");
    
            System.out.println(coffee.getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    工厂(factory)处理创建对象的细节,一旦有了SimpleCoffeeFactory,CoffeeStore类中的orderCoffee()就变成此对象的客户,后期如果需要Coffee对象直接从工厂中获取即可。这样也就解除了和Coffee实现类的耦合,同时又产生了新的耦合,CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合,工厂对象和商品对象的耦合。

    后期如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的createCoffee方法的代码,违反了开闭原则。工厂类的客户端可能有很多,比如创建美团外卖等,这样只需要修改工厂类的代码,省去其他的修改操作。

    简单工厂模式有什么优点?

    简单工厂模式封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

    简单工厂模式有什么缺点?

    增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。

    简单工厂模式还可以怎么实现?

    简单工厂模式还可以使用静态工厂的方式实现,也就是将创建对象功能定义成静态的。

    public class SimpleCoffeeFactory {
    
        public static Coffee createCoffee(String type) {
            Coffee coffee = null;
            if("americano".equals(type)) {
                coffee = new AmericanoCoffee();
            } else if("latte".equals(type)) {
                coffee = new LatteCoffee();
            }
            return coffe;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3. 工厂方法模式

    工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B4Jo4q8C-1668690825241)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/9944/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F.png)]

    工厂方法模式的主要角色:

    • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
    • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

    具体实现:

    抽象工厂

    public interface CoffeeFactory {
    
        Coffee createCoffee();
    }
    
    • 1
    • 2
    • 3
    • 4

    具体工厂

    public class LatteCoffeeFactory implements CoffeeFactory {
    
        public Coffee createCoffee() {
            return new LatteCoffee();
        }
    }
    
    public class AmericanCoffeeFactory implements CoffeeFactory {
    
        public Coffee createCoffee() {
            return new AmericanCoffee();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    咖啡店类

    public class CoffeeStore {
    
        private CoffeeFactory factory;
    
        public CoffeeStore(CoffeeFactory factory) {
            this.factory = factory;
        }
    
        public Coffee orderCoffee(String type) {
            Coffee coffee = factory.createCoffee();
            coffee.addMilk();
            coffee.addsugar();
            return coffee;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类

    public class Client {
        public static void main(String[] args) {
            //创建咖啡店对象
            CoffeeStore store = new CoffeeStore();
            //创建对象
            //CoffeeFactory factory = new AmericanCoffeeFactory();
            CoffeeFactory factory = new LatteCoffeeFactory();
            store.setFactory(factory);
    
            //点咖啡
            Coffee coffee = store.orderCoffee();
    
            System.out.println(coffee.getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    由上面的代码可见,当我们需要添加产品的时候也需要添加相应的工厂类,但是却不用修改工厂类的代码,这样就解决了简单工厂模式的缺点。

    工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

    工厂方法模式有什么优点?

    • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
    • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

    工厂方法模式有什么缺点?

    • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

    4. 抽象工厂模式

    在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体工厂对应一个具体产品,但有时候我们需要一个工厂能够提供多个产品对象,而不是单一的对象,这个时候我们就需要使用抽象工厂模式。

    image-20200401214509176

    抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

    抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

    抽象工厂模式的主要角色如下:

    • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
    • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
    • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
    • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C8tYIWEU-1668690825242)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/9944/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F.png)]

    抽象工厂

    public interface DessertFactory {
    
        Coffee createCoffee();
    
        Dessert createDessert();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    具体工厂

    //美式甜点工厂
    public class AmericanDessertFactory implements DessertFactory {
    
        public Coffee createCoffee() {
            return new AmericanCoffee();
        }
    
        public Dessert createDessert() {
            return new MatchaMousse();
        }
    }
    //意大利风味甜点工厂
    public class ItalyDessertFactory implements DessertFactory {
    
        public Coffee createCoffee() {
            return new LatteCoffee();
        }
    
        public Dessert createDessert() {
            return new Tiramisu();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    测试类

    public class Client {
        public static void main(String[] args) {
            //创建的是意大利风味甜品工厂对象
            //ItalyDessertFactory factory = new ItalyDessertFactory();
            AmericanDessertFactory factory = new AmericanDessertFactory();
            //获取拿铁咖啡和提拉米苏甜品
            Coffee coffee = factory.createCoffee();
            Dessert dessert = factory.createDessert();
    
            System.out.println(coffee.getName());
            dessert.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    抽象工厂模式有什么优点?

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

    抽象工厂模式有什么缺点?

    当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

    抽象工厂模式的应用场景有哪些?

    • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。

    • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。

    • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

    如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。

    抽象工厂模式与工厂方法模式的区别?

    1. 工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例。

    2. 抽象工厂模式拥有多个抽象产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例

    请你比较以下简单工厂模式、工厂方法模式和抽象工厂模式的异同?

    • 简单工厂模式其实并不算是一种设计模式,更多的时候是一种编程习惯。简单工厂的实现思路是,定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。
    • 工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。工厂方法的实现思路是,定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
    • 抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一个对象,而是可以创建一组对象。这是和工厂方法最大的不同点。抽象工厂的实现思路是,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

    参考:

  • 相关阅读:
    OpenCVSharp图像形态学操作
    【Java|golang】210. 课程表 II---拓扑排序
    串口通信协议
    Spring--bean生命周期
    ESP32网络开发实例-使用NTP获取当前时间
    C#实现单链表的定义、插入、删除、查找
    SpringCloud集成RocketMQ
    2.Go语言环境配置
    阿里云服务器续费流程方法_续费优惠封神教程
    LeetCode-热题100-笔记-day25
  • 原文地址:https://blog.csdn.net/weixin_51146329/article/details/127912017