设计模式-工厂模式

1. 概念

工厂(Factory)顾名思义就是创建对象实例的生产工厂。

以前创建对象都是 new Xxx(),如果使用工厂模式 的话就可以用它来替代 new 操作创建实例(对象)。所以理解了工厂模式后,以后去 new 对象时就可以考虑还能使用工厂模式达到一样的目的。虽然这样做可能需要多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量(主要是降低耦合)。

工厂模式分为三种:简单工厂模式、工厂方法模式、抽象工厂模式。

2. 简单工厂模式

2.1 概念

简单工厂模式不属于GOF的23种经典设计模式,严格来说它应该属于一种编程习惯,这个简单工厂模式只是工厂方法模式的一种特例,所以工厂模式实际上只有工厂方法模式和抽象工厂模式。

简单工厂比较适合创建对象较少的场景。

2.2 优缺点

优点:

  1. 解耦: 客户端代码与具体产品类解耦,客户端只依赖于产品接口,便于扩展和维护。
  2. 集中管理: 所有对象的创建逻辑集中在工厂类中,方便管理和修改。
  3. 简化对象创建: 客户端不需要知道具体的创建过程,只需调用工厂方法即可。

缺点:

  1. 不符合开闭原则: 当需要添加新产品时,必须修改工厂类的代码,违反了开闭原则(对扩展开放,对修改关闭)。
  2. 工厂类职责过重: 工厂类需要处理所有产品的创建逻辑,可能导致类变得庞大且复杂。
  3. 难以扩展: 如果产品种类增多,工厂类会变得越来越复杂,维护难度增加。

2.3 组成结构

  1. 产品接口(Product): 定义产品的公共接口,所有具体产品都需要实现这个接口。
  2. 具体产品(Concrete Product): 实现产品接口的具体类,代表工厂所创建的具体对象。
  3. 工厂类(Factory): 提供一个静态方法,根据不同的参数返回不同的具体产品对象。

2.4 举例

产品接口

public interface Animal {
    void sound();
}

具体产品

public class Cat implements Animal {
    @Override
    public void sound() {
        System.out.println("喵喵");
    }
}
public class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("汪汪");
    }
}

工厂类

public class AnimalFactory {
    public static Animal createAnimal(String type) {
        if (type.equalsIgnoreCase("cat")) {
            return new Cat();
        } else if (type.equalsIgnoreCase("dog")) {
            return new Dog();
        }
        return null;
    }
}

客户端使用测试

public class Test {
    public static void main(String[] args) {
        Animal cat = AnimalFactory.createAnimal("cat");
        cat.sound(); // 输出:喵喵

        Animal dog = AnimalFactory.createAnimal("dog");
        dog.sound(); // 输出:汪汪
    }
}

在这里插入图片描述

2.5 总结

简单工厂模式适用于产品种类较少且变化不大的场景,但在产品种类较多且经常变化的情况下,使用工厂方法模式或抽象工厂模式可能更为合适。

3. 工厂方法模式

3.1 概念

核心思想:将对象的创建逻辑下沉到子类里面(创建多个子工厂来创建对象)

这种方式如果再要增加新的类型时,就不需要修改工厂类的代码了,每个实例类都会有一个工厂,这样就解决了简单工厂模式的缺点,不过要相应地增加工厂类。工厂方法模式是简单工厂模式的进一步抽象,运用了多态性、克服了简单工厂模式的缺点。

3.2 优缺点

优点:获取对象时只需要知道具体工厂的名称,就可以得到对应的对象,无须知道具体创建过程;在系统增加新的类时只需要添加对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。

缺点:每增加一个类就要增加一个对应的具体工厂类,增加了系统的复杂度。

3.3 组成部分

  1. 产品接口:定义了产品的接口。
  2. 具体产品:实现了产品接口的具体类。
  3. 工厂接口:定义了创建产品的工厂方法。
  4. 具体工厂:实现了工厂接口,返回具体产品的实例。

3.4 举例

产品接口

public interface Shape {
    void draw();
}

具体产品

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}
public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a Rectangle");
    }
}

工厂接口

public interface ShapeFactory {
    Shape createShape();
}

具体工厂

public class CircleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}
public class RectangleFactory implements ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}

客户端使用

public class Test {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw(); // 输出: Drawing a Circle

        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw(); // 输出: Drawing a Rectangle
    }
}

在这里插入图片描述

3.5 总结

在这个例子中,我们定义了一个 Shape 接口和两个实现类 Circle 和 Rectangle。通过工厂接口 ShapeFactory 和其具体实现类 CircleFactory 和 RectangleFactory,我们可以根据需要创建不同的形状实例,遵循了工厂方法模式的设计理念。这样,增加新的形状只需添加新的产品类和工厂类,而无需修改现有代码,符合开闭原则。

4. 抽象工厂模式

4.1 概念

抽象工厂模式是一种创建型设计模式,提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。它通过定义一个工厂接口及其实现类来生成对象,使得客户端代码与具体类解耦。

4.2 优缺点

优点

  1. 解耦:客户端不需要知道具体类的实现,降低了系统的耦合度。
  2. 可扩展性:增加新产品系列时,只需添加新的工厂类而不影响现有代码。
    一致性:可以确保产品的创建符合一定的标准和一致性。

缺点

  1. 类的数量增加:每增加一个产品系列,就需要增加一个具体工厂,可能导致类的数量激增。
  2. 难以支持新种类的产品:如果需要添加新的产品类型,可能需要修改现有的工厂接口。

4.3 组成结构

  1. 抽象工厂(AbstractFactory):定义创建产品的接口。
  2. 具体工厂(ConcreteFactory):实现抽象工厂接口,创建具体产品。
  3. 抽象产品(AbstractProduct):定义产品的接口。
  4. 具体产品(ConcreteProduct):实现抽象产品接口的具体类。

4.4 举例

抽象产品

public interface Payment {
    void pay();
}
public interface Refund {
    void refund();
}

具体产品

public class Alipay implements Payment {
    @Override
    public void pay() {
        System.out.println("使用支付宝支付");
    }
}
public class AlipayRefund implements Refund {
    @Override
    public void refund() {
        System.out.println("使用支付宝退款");
    }
}
public class WeChatPay implements Payment {
    @Override
    public void pay() {
        System.out.println("使用微信支付");
    }
}
public class WeChatRefund implements Refund {
    @Override
    public void refund() {
        System.out.println("使用微信退款");
    }
}

抽象工厂

public interface PaymentFactory {
    Payment createPayment();
    Refund createRefund();
}

具体工厂

public class AlipayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new Alipay();
    }

    @Override
    public Refund createRefund() {
        return new AlipayRefund();
    }
}

public class WeChatPayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new WeChatPay();
    }

    @Override
    public Refund createRefund() {
        return new WeChatRefund();
    }
}

客户端使用

public class Test {
    public static void main(String[] args) {
        PaymentFactory alipayFactory = new AlipayFactory();
        Payment alipay = alipayFactory.createPayment();
        Refund alipayRefund = alipayFactory.createRefund();

        alipay.pay();
        alipayRefund.refund();

        PaymentFactory weChatFactory = new WeChatPayFactory();
        Payment weChatPay = weChatFactory.createPayment();
        Refund weChatRefund = weChatFactory.createRefund();

        weChatPay.pay();
        weChatRefund.refund();
    }
}

类图
在这里插入图片描述

4.5 总结

使用场景:

  1. 当系统需要独立于其产品的创建、组合和表示时。
  2. 当系统需要使用多个产品族中的对象时。
  3. 当产品的组合需要保持一致性时。

5 总结

简单工厂:产品的工厂。适用于简单的对象创建,适合小型项目。
工厂方法:工厂的工厂。适用于需要灵活扩展的项目,适合中型项目。
抽象工厂:复杂产品的工厂。适用于需要多个产品族的复杂系统,适合大型项目。

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值