建造者(builder)模式属于创建型模式,建造者模式一般有两种类型的应用
建造者模式中的简单版本
逐渐复杂的问题
假设现在需要创建一个用户对象,那么你会这样实现代码
class User:
def __init__(self, name):
self.name = name
user = User("jack")
后来你需要为这个用户对象引入其他的属性:生日、住址、身高、体重、兴趣,不同的用户在创建时不愿意提供其中一些信息,于是你实现了下面的版本:
class User:
def __init__(self, name, age=None,birth_date=None,address=None,heigh=None,weight=None,hobby=None):
self.name = name
self.age = age
self.birth_date = birth_date
self.address = address
self.heigh = heigh
self.weight = weight
self.hobby = hobby
user = User("John", heigh=165,weight=58,hobby="reading")
可以看到随着对象的属性越来越多,我们的构造函数的参数列表越来越长。这里由于使用了关键字参数的关系,所以问题并不明显,假如使用位置参数,那么使用者在使用时就必须记住参数的位置,甚至对于没有的属性需要放置None
值:
def __init__(self, name, age,birthday,address,heigh,weight,hobby):
...
User("Lucy",17,None,None,68,None,None)
当然这个问题也不是不能接受,让我们继续增加问题的复杂度,假如现在我们还需要对一些属性进行校验或者转化处理,那么你可能会这么修改代码:
class User:
def __init__(self, name, age=None,birth_date=None,address=None,heigh=None,weight=None,hobby=None):
self.name = name
self.age = age if isinstance(age,int) and age > 0 else None
self.birth_date = birth_date
self.address = address
self.heigh = heigh if isinstance(heigh, int) else None
self.weight = weight if isinstance(weight, int) else None
self.hobby = self.set_hobby(hobby)
def set_hobby(self, hobby):
if isinstance(hobby, list):
hobby = ",".join(hobby)
return hobby
user = User("John", heigh=165,weight=58,hobby=["reading","running"])
在这个版本中,构造参数依然很多,但set_hobby
的出现,让我们开始思考属性的添加为什么不采用调用实例函数的方式设置?于是我们修改了整个 User
的实现
class User:
def __init__(self, name):
self.name = name
self.label = None
def get_user_info(self):
return self.__dict__
def add_age(self,age:int):
if age < 0:
raise ValueError("Age should be > 0!!!")
self.age = age
def add_birthday(self,birthday):
self.birthday = birthday
def add_address(self,address:str):
self.address = address
def add_height(self,height:int):
self.height = height
def add_weight(self,weight:int):
self.weight = weight
def add_hobby(self, hobby):
if isinstance(hobby, list):
hobby = ",".join(hobby)
self.hobby = hobby
def main():
user = User("John")
user