原型方法Python设计模式
原型方法是一种创建设计模式,旨在减少用于应用程序的类的数量。它允许您复制现有对象,而与它们的类的具体实现无关。通常,这里的对象是通过在运行时复制原型实例来创建的。
当对象创建在时间和资源使用方面是一项昂贵的任务并且已经存在类似对象时,强烈建议使用原型方法。该方法提供了一种复制原始对象然后根据我们的需要进行修改的方法。
没有原型方法我们面临的问题
假设我们有一个 Shape 类,它产生不同的形状,如圆形、矩形、正方形等,并且我们已经有了它的一个对象。现在我们要创建这个对象的精确副本。一个普通的开发者会怎么走?
他/她将创建同一类的新对象,并将应用原始对象的所有功能并复制它们的值。但是我们不能复制原始对象的每个字段,因为有些字段可能是私有的和受保护的,并且不能从对象本身的外部获得。
问题还没有结束!你也会变得依赖其他类的代码,这在软件开发中肯定不是一个好的做法。
为了更好地理解,让我们了解提供 SDE、DSA、STL 等课程的Courses At GeeksforGeeks示例。一次又一次地为类似课程创建对象并不是以更好的方式利用资源的好任务。
注意:以下代码是在没有使用原型方法的情况下编写的
Python3
# concrete course
class DSA():
"""Class for Data Structures and Algorithms"""
def Type(self):
return "Data Structures and Algorithms"
def __str__(self):
return "DSA"
# concrete course
class SDE():
"""Class for Software development Engineer"""
def Type(self):
return "Software Development Engineer"
def __str__(self):
return "SDE"
# concrete course
class STL():
"""class for Standard Template Library of C++"""
def Type(self):
return "Standard Template Library"
def __str__(self):
return "STL"
# main method
if __name__ == "__main__":
sde = SDE() # object for SDE
dsa = DSA() # object for DSA
stl = STL() # object for STL
print(f'Name of Course: {sde} and its type: {sde.Type()}')
print(f'Name of Course: {stl} and its type: {stl.Type()}')
print(f'Name of Course: {dsa} and its type: {dsa.Type()}')
Python3
# import the required modules
from abc import ABCMeta, abstractmethod
import copy
# class - Courses at GeeksforGeeks
class Courses_At_GFG(metaclass = ABCMeta):
# constructor
def __init__(self):
self.id = None
self.type = None
@abstractmethod
def course(self):
pass
def get_type(self):
return self.type
def get_id(self):
return self.id
def set_id(self, sid):
self.id = sid
def clone(self):
return copy.copy(self)
# class - DSA course
class DSA(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Data Structures and Algorithms"
def course(self):
print("Inside DSA::course() method")
# class - SDE Course
class SDE(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Software Development Engineer"
def course(self):
print("Inside SDE::course() method.")
# class - STL Course
class STL(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Standard Template Library"
def course(self):
print("Inside STL::course() method.")
# class - Courses At GeeksforGeeks Cache
class Courses_At_GFG_Cache:
# cache to store useful information
cache = {}
@staticmethod
def get_course(sid):
COURSE = Courses_At_GFG_Cache.cache.get(sid, None)
return COURSE.clone()
@staticmethod
def load():
sde = SDE()
sde.set_id("1")
Courses_At_GFG_Cache.cache[sde.get_id()] = sde
dsa = DSA()
dsa.set_id("2")
Courses_At_GFG_Cache.cache[dsa.get_id()] = dsa
stl = STL()
stl.set_id("3")
Courses_At_GFG_Cache.cache[stl.get_id()] = stl
# main function
if __name__ == '__main__':
Courses_At_GFG_Cache.load()
sde = Courses_At_GFG_Cache.get_course("1")
print(sde.get_type())
dsa = Courses_At_GFG_Cache.get_course("2")
print(dsa.get_type())
stl = Courses_At_GFG_Cache.get_course("3")
print(stl.get_type())
原型法解决方案:
为了处理这样的问题,我们使用Prototype方法。我们将为Courses_At_GFG和Course_At_GFG_Cache创建单独的类,这将帮助我们创建具有相同字段属性的现有对象的精确副本。此方法将克隆过程委托给正在克隆的实际对象。在这里,我们声明了一个支持对象克隆的通用接口或类,它允许我们在不将代码耦合到该方法的类的情况下克隆对象。
支持克隆的对象称为Prototype 。
Python3
# import the required modules
from abc import ABCMeta, abstractmethod
import copy
# class - Courses at GeeksforGeeks
class Courses_At_GFG(metaclass = ABCMeta):
# constructor
def __init__(self):
self.id = None
self.type = None
@abstractmethod
def course(self):
pass
def get_type(self):
return self.type
def get_id(self):
return self.id
def set_id(self, sid):
self.id = sid
def clone(self):
return copy.copy(self)
# class - DSA course
class DSA(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Data Structures and Algorithms"
def course(self):
print("Inside DSA::course() method")
# class - SDE Course
class SDE(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Software Development Engineer"
def course(self):
print("Inside SDE::course() method.")
# class - STL Course
class STL(Courses_At_GFG):
def __init__(self):
super().__init__()
self.type = "Standard Template Library"
def course(self):
print("Inside STL::course() method.")
# class - Courses At GeeksforGeeks Cache
class Courses_At_GFG_Cache:
# cache to store useful information
cache = {}
@staticmethod
def get_course(sid):
COURSE = Courses_At_GFG_Cache.cache.get(sid, None)
return COURSE.clone()
@staticmethod
def load():
sde = SDE()
sde.set_id("1")
Courses_At_GFG_Cache.cache[sde.get_id()] = sde
dsa = DSA()
dsa.set_id("2")
Courses_At_GFG_Cache.cache[dsa.get_id()] = dsa
stl = STL()
stl.set_id("3")
Courses_At_GFG_Cache.cache[stl.get_id()] = stl
# main function
if __name__ == '__main__':
Courses_At_GFG_Cache.load()
sde = Courses_At_GFG_Cache.get_course("1")
print(sde.get_type())
dsa = Courses_At_GFG_Cache.get_course("2")
print(dsa.get_type())
stl = Courses_At_GFG_Cache.get_course("3")
print(stl.get_type())
原型设计模式UML图
好处
- 更少的子类:所有其他创建设计模式都提供了许多新的子类,当我们在处理大型项目时,这些子类肯定不容易处理。但是使用原型设计模式,我们摆脱了这一点。
- 为新对象提供不同的值:所有高度动态的系统都允许您通过对象组合来定义新行为,方法是指定对象变量的值,而不是定义新类。
- 为新对象提供不同的结构:通常所有应用程序都从部件和子部件构建对象。为方便起见,此类应用程序通常允许您实例化复杂的用户定义结构,以一次又一次地使用特定的子电路。
缺点
- 抽象:它通过隐藏类的具体实现细节来帮助实现抽象。
- 较低级别的资源浪费:对于使用很少对象的项目,这可能被证明是资源的过度杀伤
适用性
- 独立于具体类:原型方法提供了实现新对象的方法,而不依赖于类的具体实现。
- 反复出现的问题:原型法也用于解决软件开发中反复出现的复杂问题。
进一步阅读Java中的原型设计模式