【Python设计模式】03 工厂模式:建立创建对象的工厂

版权声明:欢迎转载 https://blog.csdn.net/Yuyh131/article/details/83176371

三、工厂模式:建立创建对象的工厂

工厂模式可以说是最常用的设计模式
本章主要介绍创建型设计模式:工厂模式

本章主题

  • 了解简单工厂设计模式
  • 讨论工厂方法和抽象工厂方法及其差异
  • 利用Python 代码实现真实场景
  • 讨论模式的优缺点并进行相应的比较

1. 了解工厂模式

面向对象编程中,‘工厂’ 表示一个负责创建其他类型对象的类

工厂与客户端的关系:

  • 工厂的类创建一个对象以及与这个对象关联的多个方法
  • 客户端使用某些参数调用此方法
  • 工厂会据此创建所需类型的对象,然后将它们返回给客户端

那么问题是为什么不能是客户端直接创建对象呢?工厂的优点在于:

  • 松耦合,即对象的创建可以独立于类的实现
  • 客户端无需了解创建对象的类,只需要知道需要传递的接口、方法和参数,简化了客户端的实现
  • 轻松地在工厂中添加其他类来创建其他类型的对象,而这无需更改客户端代码
  • 工厂可以重用现有对象。但是客户端创建对象总是创建一个新的对象

Factory 设计模式有三种变体:

  • 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑
  • 工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则交由子类决定
  • 抽象工厂模式:抽象工厂是一个能够创建一系列相关对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象

2. 简单工厂模式

工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化

from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
	@abstractmethod
	def do_say(self):
		pass

class Dog(Animal):
	def do_say(self):
		print("Wong Wong!!")

class Cat(Animal):
	def do_say(self):
		print("Miao Miao!!")


## forest factory defined
class ForestFactory(object):
	def make_sound(self, object_type):
		return eval(object_type)().do_say()
	
## client code
if __name__ == '__main__':
	ff = ForestFactory()
	animal = input("Which animal should make_sound Dog or Cat?")
	ff.make_sound(animal)

运行结果:
Which animal should make_sound Dog or Cat?Cat
Miao Miao!!

3. 工厂方法模式

工厂方法模式要点:

  • 我们定义了一个接口来创建,但是工厂本身并不负责创建对象,而是将这个任务交由子类来完成,即子类决定了要实例化哪些类
  • 工厂方法的创建是通过继承而不是通过实例化来完成的
  • 工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某些类型的对象(就像在简单工厂方法中的那样)

实现工厂方法:
假设我们想在不同类型的社交网站(例如:LinkedIn、Facebook)上为个人或公司建立简介
那么每个简介都有某些特定的组成章节
LinkedIn: 个人专利或出版作品区 + 个人信息区
Facebook: 在相册中度假的照片区 + 个人信息区
简言之,我们通过将正确的区添加到相应的简介中来创建不同类型的简介

from abc import ABCMeta, abstractmethod


class Section(metaclass=ABCMeta):
	@abstractmethod
	def describe(self):
		pass


class PersonalSection(Section):
	def describe(self):
		print("个人信息 Section")


class AlbumSection(Section):
	def describe(self):
		print("相册 Section")


class PatentSection(Section):
	def describe(self):
		print("专利区 Section")


class PublicationSection(Section):
	def describe(self):
		print("出版作品 Section")

我们创建一个Profile抽象类,提供一个工厂方法createProfile(),创建相应的简介
工厂方法类:只提供了接口,并没有实际创建类
子类决定使用哪些区

class Profile(metaclass=ABCMeta):
	def __init__(self):
		self.sections = []
		self.createProfile()

	@abstractmethod
	def createProfile(self):
		pass

	def getSections(self):
		return self.sections

	def addSections(self, section):
		self.sections.append(section)	
	

class linkedin(Profile):
	def createProfile(self):
		self.addSections(PersonalSection())
		self.addSections(PatentSection())
		self.addSections(PublicationSection())


class facebook(Profile):
	def createProfile(self):
		self.addSections(PersonalSection())
		self.addSections(AlbumSection())


if __name__ == "__main__":
	profile_type = input("Which Profile you'd like to create? \
					[LinkedIn or FaceBook]")
	profile = eval(profile_type.lower())()
	print("Creating Profile..", type(profile).__name__)
	print("Profile has sections --", profile.getSections())

运行结果:
Which Profile you’d like to create? [LinkedIn or FaceBook]facebook
Creating Profile… facebook
Profile has sections – [<main.PersonalSection object at 0x7fb4c03bff28>,
<main.AlbumSection object at 0x7fb4c03bf780>]

可以发现:工厂方法里面的工厂不创建类,只提供接口
facebook选定后,facebook类就被实例化,Profile中的__init__方法被调用,
–> __init__中的createProfile()方法被调用 --> addSections被调用,
–> Section列表的append()方法被调用

4. 工厂方法模式的优点

  • ta具有更大的灵活性,代码更加通用,因为它不是单纯地实例化某个类。这样实现哪些类取决于接口
  • 松耦合,因为创建对象的代码与使用它的代码是分开的。客户端无需关心传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本

5. 抽象工厂模式

抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类
抽象工厂的目标是创建一系列相关对象,而工厂方法模式将创建实例的任务交给了子类
实际上,抽象工厂模式不仅确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象
但是客户端只能通过接口访问对象

from abc import ABCMeta, abstractmethod

# 抽象工厂基类:pizza factory
class PizzaFactory(metaclass=ABCMeta):
	@abstractmethod
	def createVegPizza(self):
		pass
	
	@abstractmethod
	def createNonVegPizza(self):
		pass

# Indian pizza factory
class IndianPizzaFactory(PizzaFactory):
	def createVegPizza(self):
		return DeluxVeggiePizza()

	def createNonVegPizza(self):
		return ChickenPizza()

# USA pizza factory
class USPizzaFactory(PizzaFactory):
	def createVegPizza(self):
		return MexicanVegPizza()

	def createNonVegPizza(self):
		return HamPizza()


class VegPizza(metaclass=ABCMeta):
	@abstractmethod
	def prepare(self, VegPizza):
		pass


class NonVegPizza(metaclass=ABCMeta):
	@abstractmethod
	def serve(self, VegPizza):
		pass


class DeluxVeggiePizza(VegPizza):
	def prepare(self):
		print("Prepare ", type(self).__name__)


class ChickenPizza(NonVegPizza):
	def serve(self, VegPizza):
		print(type(self).__name__, "is served with Chicken on ", \
			type(VegPizza).__name__)


class MexicanVegPizza(VegPizza):
	def prepare(self):
		print("Prepare ", type(self).__name__)


class HamPizza(NonVegPizza):
	def serve(self, VegPizza):
		print(type(self).__name__, "is served with Ham on ", \
			type(VegPizza).__name__)


class PizzaStore:
	def __init__(self):
		pass
	
	def makePizza(self):
		for factory in [IndianPizzaFactory(), USPizzaFactory()]:
			self.factory = factory
			self.NonVegPizza = self.factory.createNonVegPizza()
			self.VegPizza = self.factory.createVegPizza()
			self.VegPizza.prepare()
			self.NonVegPizza.serve(self.VegPizza)


pizza = PizzaStore()
pizza.makePizza()

运行结果:
Prepare DeluxVeggiePizza
ChickenPizza is served with Chicken on DeluxVeggiePizza
Prepare MexicanVegPizza
HamPizza is served with Ham on MexicanVegPizza

解析:

  • 与工厂方法的主要区别是: 将工厂多了一层抽象,它创建的不是一个对象而是一类对象
  • 本例中,当创建工厂后,会同步创建蔬菜披萨和非蔬菜披萨两个类

6. 工厂方法与抽象工厂方法的区别

工厂方法 抽象工厂方法
它向客户端开放了一个创建对象的方法 抽象工厂包含了一个或多个工厂方法来创建一系列的相关对象
它使用继承和子类来决定要创建哪个对象 它使用组合将创建对象的任务委托给其他类
工厂方法用于创建一个产品 抽象工厂用于创建相关产品系列

7. 小结

1、介绍了工厂设计模式及其使用的上下文; 如何在软件架构有效使用工厂模式
2、简单工厂模式:可以运行时根据客户端传入的参数类型来创建相应的实例
3、工厂方法模式:定义一个接口创建对象,但是对象的实例化交给子类
4、抽象工厂模式:提供接口,无需指定具体的类就能创建一系列的相关对象
5、Python实现3种工厂模式,并比较了工厂方法与抽象工厂方法的区别

猜你喜欢

转载自blog.csdn.net/Yuyh131/article/details/83176371