chatGPT教你设计模式[2] ——创建型模式(工厂模式)
Posted 刘炫320
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了chatGPT教你设计模式[2] ——创建型模式(工厂模式)相关的知识,希望对你有一定的参考价值。
1. 引言
在软件开发中,我们经常需要创建对象来封装数据和实现业务逻辑。然而,如果直接在代码中使用 new 关键字来创建对象,会使得代码的耦合度增加,系统的可扩展性和可维护性降低。这时,工厂模式就派上用场了。
工厂模式是软件设计模式中最常用的创建型模式之一,它提供了一种创建对象的最佳方式。工厂模式可以将对象的创建和使用分离开来,使得代码更加灵活,并且提高了系统的可扩展性和可维护性。
在工厂模式中,我们通常有三种实现方式:简单工厂模式、抽象工厂模式和工厂方法模式。在本篇博客中,我们将深入介绍这三种工厂模式的基本概念、结构、优缺点和应用场景,帮助你更好地理解和应用这些模式。
2 简单工厂模式
简单工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。
在简单工厂模式中,有一个工厂类,该类负责创建其他类的实例。工厂类包含一个用于创建对象的方法,该方法通过传递参数来决定要创建哪种对象。
例如,假设我们有一个用于创建不同类型的形状的工厂类,我们可以使用如下代码实现它:
class ShapeFactory:
@staticmethod
def get_shape(shape_type):
if shape_type == 'circle':
return Circle()
elif shape_type == 'square':
return Square()
elif shape_type == 'rectangle':
return Rectangle()
class Circle:
def draw(self):
print("Drawing a circle")
class Square:
def draw(self):
print("Drawing a square")
class Rectangle:
def draw(self):
print("Drawing a rectangle")
# usage
factory = ShapeFactory()
shape = factory.get_shape("circle")
shape.draw() # Output: Drawing a circle
在这个例子中,我们定义了一个 ShapeFactory 类,它包含一个静态方法 get_shape,该方法接收一个字符串参数,用于决定要创建哪种形状。我们还定义了三个形状类,分别是 Circle、Square 和 Rectangle,每个类都有一个 draw 方法,用于绘制形状。
通过调用工厂类的 get_shape 方法,我们可以轻松地创建不同类型的形状,而无需要直接使用具体的形状类,这样我们就可以避免在代码中出现大量的条件语句。
2.1. 模式优缺点
简单工厂模式的优点在于,它可以使代码的可读性和可维护性提高,因为它隐藏了具体的实现细节,只暴露了一个简单的接口供外界调用。
但是,简单工厂模式也有一些缺点。首先,如果需要增加新的类型,则必须修改工厂类的代码,这违反了“开放-封闭原则”。其次,如果需要增加新的类型,则必须对工厂类进行测试,以确保修改后的代码仍然能够正常工作。
2.2 模式结构
简单工厂模式的结构如下:
- 工厂类角色:它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
- 抽象产品角色:它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法。
- 具体产品角色:它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。
在设计模式中,简单工厂模式是一种比较简单的创建型模式,它适用于只有少数产品类的场景,但如果产品类数量较多,就会导致工厂类的代码变得臃肿,不利于维护。因此,在设计模式中,简单工厂模式通常被视为一种“过渡”模式,它可以帮助开发人员理解工厂模式的基本思想,并为进一步学习更高级的工厂模式(如工厂方法模式和抽象工厂模式)打下基础。
3 抽象工厂模式
抽象工厂模式是一种创建型设计模式,它提供了一种创建相关或依赖对象的最佳方式。
在抽象工厂模式中,有一个抽象工厂类,它包含多个用于创建不同类型对象的抽象方法。具体工厂类继承抽象工厂类,并实现抽象方法,从而创建具体的对象。
与简单工厂模式相比,抽象工厂模式更加灵活,因为它允许开发人员创建不同的工厂类来生成不同的对象。这样,在新增类型时,只需要创建新的具体工厂类和相应的对象类,就不需要修改已有的代码。
例如,假设我们有一个抽象工厂类用于创建不同类型的车辆,我们可以使用如下代码实现它:
class VehicleFactory:
def get_vehicle(self, vehicle_type):
pass
class CarFactory(VehicleFactory):
def get_vehicle(self, vehicle_type):
if vehicle_type == 'small':
return SmallCar()
elif vehicle_type == 'medium':
return MediumCar()
elif vehicle_type == 'large':
return LargeCar()
class BikeFactory(VehicleFactory):
def get_vehicle(self, vehicle_type):
if vehicle_type == 'small':
return SmallBike()
elif vehicle_type == 'medium':
return MediumBike()
elif vehicle_type == 'large':
return LargeBike()
class SmallCar:
def __str__(self):
return "Small Car"
class MediumCar:
def __str__(self):
return "Medium Car"
class LargeCar:
def __str__(self):
return "Large Car"
class SmallBike:
def __str__(self):
return "Small Bike"
class MediumBike:
def __str__(self):
return "Medium Bike"
class LargeBike:
def __str__(self):
return "Large Bike"
# usage
car_factory = CarFactory()
bike_factory = BikeFactory()
small_car = car_factory.get_vehicle("small")
print(small_car) # Output: Small Car
medium_car = car_factory.get_vehicle("medium")
print(medium_car) # Output: Medium Car
large_car = car_factory.get_vehicle("large")
print(large_car) # Output: Large Car
small_bike = bike_factory.get_vehicle("small")
print(small_bike) # Output: Small Bike
medium_bike = bike_factory.get_vehicle("medium")
print(medium_bike) # Output: Medium Bike
large_bike = bike_factory.get_vehicle("large")
print(large_bike) # Output: Large Bike
在这个例子中,我们定义了一个抽象工厂类 VehicleFactory,它包含一个抽象方法 get_vehicle,用于创建车辆对象。我们还定义了两个具体工厂类,分别是 CarFactory 和 BikeFactory,它们分别继承了 VehicleFactory 类并实现了 get_vehicle 方法。
通过调用具体工厂类的 get_vehicle 方法,我们可以轻松地创建不同类型的车辆对象,而无需直接使用具体的车辆类。
3.1 模式优缺点
优点:
-
封装性好
抽象工厂模式隔离了具体类的生成,使得用户不需要知道什么被创建。用户只需要知道所对应的工厂即可得到所需要的产品,而无需关心创建细节。 -
产品族内的约束是更少的
抽象工厂模式中的抽象工厂角色只需要提供多个生成产品的方法,这样,在系统中只需要有抽象工厂的具体实现类对应的具体产品即可。
缺点:
-
产品族扩展麻烦
抽象工厂模式需要增加新的产品族时,需要修改抽象工厂和所有的具体工厂类,这违背了“开闭原则”。 -
产品等级结构扩展麻烦
抽象工厂模式需要增加新的产品等级结构时,需要修改抽象工厂和所有的具体工厂类,这也违背了“开闭原则”。
3.2 模式结构
抽象工厂模式是一种创建型设计模式,它提供一种方法来创建一组相关或相互依赖的对象,而无需指定它们具体的类。抽象工厂模式有四个要素:
抽象工厂类:抽象工厂类是工厂模式的核心,它声明了创建所有产品对象的方法。
具体工厂类:具体工厂类是抽象工厂类的子类,它实现了在抽象工厂中声明的创建产品的方法。
抽象产品类:抽象产品类是工厂模式所创建的对象的超类型,声明了产品对象的主要特征和功能。
具体产品类:具体产品类是抽象产品类的子类,它实现了抽象产品类中声明的方法,构成了具体的产品对象。
总的来说,抽象工厂模式是一种很有用的设计模式,它能够提供一组相关的产品对象,而无需指定它们的具体类。但是,在实际使用中,需要注意增加新的产品等级结构可能会比较困难,因此需要谨慎使用。
3. 工厂方法模式
工厂方法模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。
在工厂方法模式中,有一个抽象工厂类,它包含一个抽象方法用于创建对象。具体工厂类继承抽象工厂类,并实现抽象方法,从而创建具体的对象。
与抽象工厂模式相比,工厂方法模式更加灵活,因为它允许开发人员创建不同的工厂类来生成不同的对象,而不需要修改已有的代码。
例如,假设我们有一个抽象工厂类用于创建不同类型的车辆,我们可以使用如下代码实现它:
from abc import ABC, abstractmethod
class VehicleFactory(ABC):
@abstractmethod
def get_vehicle(self):
pass
class CarFactory(VehicleFactory):
def get_vehicle(self):
return Car()
class BikeFactory(VehicleFactory):
def get_vehicle(self):
return Bike()
class Car:
def __str__(self):
return "Car"
class Bike:
def __str__(self):
return "Bike"
# usage
car_factory = CarFactory()
car = car_factory.get_vehicle()
print(car) # Output: Car
bike_factory = BikeFactory()
bike = bike_factory.get_vehicle()
print(bike) # Output: Bike
在这个例子中,我们通过调用具体工厂类的 get_vehicle 方法来创建车辆对象。
3.1 模式优缺点
优点:
-
在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到子类中完成,即由子类来决定究竟应该实例化哪一个类。
-
工厂方法模式通过使用面向对象的编程技巧,实现了在不修改具体工厂角色的情况下引进新的产品。
-
工厂方法模式在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其代码。
缺点:
-
在添加新产品时,需要编写新的具体产品类和对应的具体工厂类,这增加了系统的复杂度。
-
如果产品类型较多,则会有较多的具体工厂和具体产品类,增加了系统的维护难度。
3.2 模式结构
工厂方法模式的结构如下所示:
抽象工厂(Abstract Factory):它是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Factory):它实现了抽象工厂中定义的接口,并且负责生产一种具体的产品。一个应用程序通常只需要一个具体工厂类。
抽象产品(Abstract Product):它是工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product):它是继承了抽象产品类的具体类,每一个具体产品都提供了唯一的功能。
客户端(Client):它是使用工厂方法模式的角色,它需要创建一个产品对象,但是它并不知道具体的产品类,只需要知道所对应的工厂即可。
工厂方法模式是比较简单的,它用来创建一类产品,而且在添加新产品时,无须修改抽象工厂和抽象产品提供的接口,也无须修改客户端。但它同时也有一些缺点,需要编写新的具体产品类和对应的具体工厂类,这增加了系统的复杂度。此外,如果产品类型较多,则会有较多的具体工厂和具体产品类,增加了系统的维护难度。
总的来说,工厂方法模式是一种非常实用的设计模式,适用于在不同条件下创建不同对象的场景。它比简单工厂模式和抽象工厂模式更加灵活,能够满足更复杂的需求。
4 抽象工厂模式和工厂方法模式比较
4.1 两者的区别
抽象工厂模式和工厂方法模式是两种常用的工厂模式,它们都用于解决在软件开发中对象的创建问题。但是两者还是有一些区别的。
首先,抽象工厂模式的目的是为了创建一组相关的或相互依赖的产品,而工厂方法模式的目的是为了创建一类产品。
其次,抽象工厂模式的结构较复杂,它需要定义抽象工厂类、具体工厂类、抽象产品类和具体产品类,而工厂方法模式的结构较简单,它只需要定义抽象工厂类、具体工厂类和具体产品类。
最后,抽象工厂模式的扩展性较差,当需要增加新的产品族时,需要修改抽象工厂类的源代码,而工厂方法模式的扩展性较好,只需要增加新的具体工厂类和具体产品类即可。
总的来说,抽象工厂模式适用于创建一组相关的或相互依赖的产品,而工厂方法模式适用于创建一类产品。在选择使用哪种工厂模式时,应该根据具体的需要和情况来决定。
4.2 两者的联系
工厂方法模式是抽象工厂模式的简化版,它将抽象工厂模式中的抽象产品类去掉,只保留具体产品类和抽象工厂类。这就使得工厂方法模式的结构比抽象工厂模式更加简单。
同时,在工厂方法模式中,具体工厂类的职责也比较单一,只需要负责生产具体产品,不需要负责生产多个产品等职责。这也使得工厂方法模式比抽象工厂模式更加简单。
在某些情况下,缺少抽象产品类可能会使工厂方法模式的结构变得更加复杂。
举个例子,假设你的系统中有一类产品,比如电子产品,它可以有手机、电脑等不同的产品。如果你使用工厂方法模式来实现这个系统,那么你需要为每种产品都定义一个具体产品类,比如 MobilePhone、Computer 等。
但是,如果你使用抽象工厂模式来实现这个系统,你可以将所有的产品都定义在一个抽象产品类的子类中,比如 Product 类的子类 MobilePhone、Computer 等。这样,就可以避免定义多个具体产品类,使得系统的结构变得更加简单。
总的来说,工厂方法模式的优点在于它的结构比较简单,实现较为容易。但是,在某些情况下,缺少抽象产品类可能会使得系统的结构变得更加复杂,不利于代码的维护和扩展。所以,在使用工厂方法模式时,如果需要添加新的具体产品类,就需要修改工厂类的代码,这违背了开闭原则。如果有多个产品族,就需要定义多个工厂类,这会增加系统的复杂度。
如果使用抽象工厂模式,就可以在不修改工厂类的情况下,通过增加新的具体产品类和抽象产品类来扩展系统,同时也可以很方便地支持多个产品族。
因此,抽象工厂模式在支持多个产品族和扩展性较强的场景中更为适用,而工厂方法模式则适用于只有一个产品族且扩展性不是很强的场景。
4.3 如何选择两者的使用?
工厂方法模式和抽象工厂模式都有各自的优点和适用场景。
抽象工厂模式适用于需要创建一组相关或相互依赖的产品的场景,比如需要同时创建一个汽车、一个发动机和一个轮胎。在这种情况下,抽象工厂模式可以满足需求,因为它能够提供一个规范,用于定义所有可能被创建的产品对象的接口,并负责提供这些产品对象的具体实例。
然而,在一些情况下,可能并不需要创建一组相关或相互依赖的产品,只需要创建一个单独的产品对象就可以了。在这种情况下,使用抽象工厂模式可能会显得多余,因为它提供的功能超出了实际需求。这就是工厂方法模式的优势所在。
工厂方法模式只需要一个工厂接口和若干个具体工厂类,就能实现对单个产品的创建。比如,只需要创建一个汽车,就可以使用工厂方法模式。它比抽象工厂模式更简单,代码量也更少,更容易理解。但是,如果我们的系统需要支持多种产品,并且所有的产品都在一个产品族内,那么抽象工厂模式是更好的选择。如果只需要支持一种产品,那么工厂方法模式是更好的选择。
5. 小结
在本篇博客中,我们介绍了三种常用的工厂模式:简单工厂模式、抽象工厂模式和工厂方法模式。
简单工厂模式是最简单的工厂模式,它通过一个工厂类来负责创建其他对象。简单工厂模式的优点在于实现简单,但是缺点是不够灵活,不能应对新的需求变化。
抽象工厂模式是一种比较高级的工厂模式,它能够创建多个产品族的产品。抽象工厂模式的优点在于能够应对新的需求变化,但是缺点是实现较复杂。
工厂方法模式是一种常用的工厂模式,它使用一个抽象工厂来负责创建一组相关的产品。工厂方法模式的优点在于能够应对新的需求变化,并且实现较为灵活。
通过本篇博客的内容,我们已经深入了解了简单工厂模式、抽象工厂模式和工厂方法模式的基本概念、结构、优缺点和应用场景。希望本篇博客能够为你的学习带来帮助,并吸引你持续关注该博客。
以上是关于chatGPT教你设计模式[2] ——创建型模式(工厂模式)的主要内容,如果未能解决你的问题,请参考以下文章
chatGPT教你设计模式[2] ——创建型模式(工厂模式)
chatGPT教你设计模式[3] ——创建型模式(单例模式建造者模式和原型模式)
chatGPT教你设计模式[3] ——创建型模式(单例模式建造者模式和原型模式)