5.Python的语言特点
前言
python有哪些语言特点?可以列出的特点很多,例如,《python核心编程》第二版列出了十多条特点。本文的三个特点是笔者学习python的体会,其他特点有体会之后再写,笔者是这样概括的:python是解释性和编译性结合的、动态的、面向对象的。
解释性和编译性
解释性是指高级语言程序运行的时候依赖于解析器将程序翻译成计算机能理解的低级语言指令,编译性指高级语言运行前先编译成计算机可执行目标低级语言,然后让计算机执行。由于解释型语言在运行过程中仍需解释器逐句翻译而编译型语言只要编译好就可以直接执行而无需再解释,所以相对来说,编译型语言的运行速度快,即性能高。笔者认为,python语言是解释性和编译性混合的。下面多余的展开也就这个意思。
计算机无法识别和执行高级语言,一个高级语言程序在可执行之前先要翻译成一种能被计算机执行的低级语言,这没有贬低的意思,方便而已。而完成这项翻译工作的就是语言处理器,常见的有编译器和解释器。编译器可以将某种高级语言程序翻译成等价的目标语言程序,以被计算机执行。解释器则是在程序文件运行的过程中将其逐句翻译成计算能看懂的指令(二进制码)。由于编译型语言一经编译成目标语言程序,计算机马上可以执行,而解释型在程序运行时还要慢慢的解释每一句给计算机执行,所以,一般来说解释型语言运行速度比编译型的慢;所以把用户输入映射成输出的过程中,由一个编译器产生的机器语言目标程序要比由一个解释器快,也就是编译型的性能好。
然而为什么还存在解释型呢?当然是由于解释型相对于编译型的一些优点,比如动态(也是缺点,不过笔者认为是优大于缺,而动态和解释性相关,不同观点勿见怪)等。所以为了兼顾性能与开发效率,某些语言自然混合了解释性和编译性。笔者认为,python程序的执行是混合了解释性和编译性的:当程序执行时,python内部(这是一个抽象)先将源程序(即我们编写的程序)编译成“字节码”,这个过程是我们看不见的,即被隐藏起来了,如果python进程在机器上拥有写入权限,那么,它将把程序的字节码保存为一个以.pyc为扩展名的文件(这是一个优化性能的步骤:在下次运行该程序时,如果程序没有变化,那么解释器将直接加载这个文件从而跳过了编译这个步骤以提高速度),然后再发送给虚拟机。字节码一旦发送给虚拟机(pvm),虚拟机便开始逐条执行翻译(如下图)。字节码并不是cpu码(二进制码),所以执行起来相对编译后的二进制码仍然是慢。
不知道为啥图片要刷新才会显示@博客园团队
动态的
动态,相对于静态,意味着随时可变,意为灵动。也可以称之为动态类型:类型由代码运行过程中自行决定,无需声明强调,而静态类型则是在运行前决定。
变量
python的变量就是在特定的时间引用一个特定的对象,不同的变量可以引用同一个对象,所以对象地址也是相同的,对象的类型必须是明确的,而所有对象首先必须要知道自己的类型(解析器能够判断,例如对象3知道自己的类型是int),这样的赋值才是有意义,像单纯一句“a=b”这样的变量引用是错误的,因为解释器无法在其作用域中判断出对象b的类型。类型属于对象而不是变量名,所以无需指明变量的类型。
变量的引用和内存管理相关,可以查找引用计数和垃圾回收方面的资料,祥略。
>>> a=1 >>> a=0.5 >>> a='a' >>> a=[] >>> type(1) <class 'int'> >>> type(0.5) <class 'float'> >>> type('a') <class 'str'> >>> type([]) <class 'list'> >>> a=b traceback (most recent call last): file "<pyshell#16>", line 1, in <module> a=b nameerror: name 'b' is not defined
参数
python中,参数通过赋值传递,赋值相当于变量的引用,自然,函数和方法中的参数的值和类型也都是动态的,这些参数的值只有在被调用的时候定义,而非在函数内定义。其实,函数定义内的参数是形参,而调用时提供给参数的的值则为实参,参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式提供值。由于数字不能作为变量,这样的赋值语句是会引发异常的:4=3,如果将函数作为一个参数,即将函数对象被引用,那么该函数就是一个回调函数。
>>> def add(x=1, y=2): # 动态参数 return x+y >>> add() 3 >>> add(2,3) 5 >>> add('a','b') 'ab' >>> add([1],[2,3]) [1, 2, 3] >>> 4=3 # 数字不能作为变量 syntaxerror: can't assign to literal >>> def call_back(i): # 回调函数 print(i) >>> def call(i, func): func(i) >>> call((1,2,3,4,5),call_back) (1, 2, 3, 4, 5)
类对象
类是面向对象常用的方法,在python中定义了类也是很“动态”的,前一篇文章说过,类相当于一个理想模型--模具,所以类实例都具有类的某些共同的特性,但每个类实例又有不同的地方,动态属性和动态方法也是造成这种差异的原因。再次强调,所谓动态,是指运行过程中的变化。
动态属性
>>> class spider: def __init__(self, url): self.url=url # 要引用url属性,url就要作为参数添加到括号里 >>> s=spider(url='https://music.163.com/') # 实例化,不带括号则指向类本身而不是实例对象,由于__init__方法的原因,必须给类提供一个参数url >>> s.cookies="cookies" # 运行过程中绑定类属性 >>> s.cookies 'cookies'
动态方法
要在运行过程中实现方法的绑定,需要借助于types模块中的methodtype方法,methodtype方法需要传递两个参数,第一个是function,第二个是instance。
>>> class spider: def __init__(self, url): self.url=url >>> s=spider(url='https://music.163.com/') >>> import types >>> def parse(self): print('retrun the txt') >>> s.parse=types.methodtype(parse, s) >>> s.parse() retrun the txt
面向对象(object)
声明一下,以下全是个人在写这部分内容的想法细节,所以会很啰嗦@唐三藏,如果看官不想看,笔者不想浪费大家的时间。但笔者相信有人想看的,毕竟人最想看到的东西就是人自己遮住的东西。当然笔者更希望的是能帮助到别人,和笔者同样处境的人。
面向对象的基本思想
对象(object)是什么?可以理解为男朋友和女朋友吗?好像不太符合现阶段,好像也可以···这样理解比较复杂。笔者的理解是:对象是类的实例化。编程对象是具有特定标识地址、属性值和方法的事物,面向对象其实就是通过创建一个理想模型来“生产”对象,这个理想模型就是类,而对象就是一个个实例化后的类,对象具有类的属性和方法,方法往往可以调用属性。例如创建一个抽象模型--person,赋予属性(name、age)和方法(say_hello),这个say_hello方法就是调用了p本身并利用了属性name的值。然后就可以这个类来“生产“不同的person实例,比如jack,比如mark···,
>>> class person: def __init__(self, name, age): self.name=name self.age=age def say_hello(self): print('hello, my name is %s'%self.name) >>> p=person('jack',23) # 由于__init__方法的原因,必须提供两参数,不能这样实例化:p=person() >>> p.name 'jack' >>> p.age 23 >>> p.say_hello() # 这里就不用提供参数了,这也是方法(类的方法)和函数的唯一区别 hello, my name is jack >>> p=person('mark',24) >>> p.name 'mark' >>> p.age 24 >>> p.say_hello() hello, my name is mark >>>
设计模式(工厂模式)
设计模式和面向对象密切相关,关于设计模式的内容太大,这里只简单说下工厂模式,工厂模式属于创建型模式,又可分为简单工厂模式、工厂方法模式、抽象工厂模式三种。这里以设计模式教程中的制造pizza为列子。再次重复强调,面向对象就是要创建理想模型,然后实例化这个模型,继而模拟现实的物件。好吧,原谅我沉溺于柏拉图的理想模型吧(个人观点)。所以,我们要创建pizza的模型和实例化pizza对象!
如何去设计pizza呢?依据pizza这个物件在现实情况,很容易就代入了pizza的卖家和买家,我们的理想模型要模拟的就是卖家,而实例化的过程是模拟买家的过程(最后我们的口号就是是卖家多卖钱,买家少花钱······,别信!)。
如何去模拟卖家和买家呢?既然是面向对象,当先从对象——买家的角度出发,考虑到生活实际,当我们想吃pizza的时候,首先要看下有哪些可以种类的pizza选择,例如有海鲜pizza——seafoodpizza,你想吃这个,然后你就会去买这个pizza或者网上订购这个piazza,假如是在网上订购,卖家肯定是需要提供给你进入这家piazza店——pizzastore的一个店的入口,然后让顾客去选择这个seafoodpizza?
如何提供呢?我们要做的当然是写一个程序,当买家与这个程序交互的时候,提供piazza的种类给买家选择。所以,这个程序应该是什么样的呢?看官不用在意笔者的思路,不同的人有不同的观点,况且笔者的观点浅薄不堪! 笔者是这么想的,先定义一个seafoodpiazza,然后再定义一个主程序作为入口,当顾客进入了这个入口,就可以选择自己喜欢的pizza,当顾客选择了自己想要的pizza之后,剩下的就是pizza店的事情了。
那么pizza店在接收到订单之后要如何处理这个海鲜pizza订单呢?笔者不知道怎么做海鲜pizza,不过笔者知道做海鲜pizza的流程应该是一个自动化的流程,包含了一些步骤,而这些步骤将会是一些类方法,然后我们去调用这些方法去把pizza做出来。看到教程的做法是这样的,如此这般,准备pizza——prepare()、烤pizza——bake()、切pizza——cut()、 包装——box()。蛋刀直入,直接就创建一个海鲜pizza!
定义好如何做pizza之后,又如何去调用这些方法呢?当然是"'对象'+'点'+'方法'”这样调用,而这个对象就是实例化的seafoodpizza——seafoodpizza()!代码如下(但请千万不要这么写):
class seafoodpizza: def prepare(self): return 'prepare seafood_pizza' def bake(self): return 'bake seafood_pizza' def cut(self): return 'cut seafood_pizza' def box(self): return 'box seafood_pizza' def orderpizza(self): # 这个self就是我们下面将要实例化的seafoodpizza——seafoodpizza() print(self.prepare()) print(self.bake()) print(self.cut()) print(self.box()) def main(): pizza = input('you will order seafood_pizza,please enter yes or no\n') # 放在循环外便于返回 while true: if pizza == 'yes': pizza = seafoodpizza() pizza.orderpizza() print('seafood_pizza completed') pizza = input('you have order seafood_pizza, anything else? yes or no\n ') elif pizza == 'no': print('bye') return else: pizza = input('please enter yes or no\n') # 返回pizza获取用户输入 if __name__ == '__main__': main()
好了,what,why,how,what,how,why;why,what,how;what······头晕······且慢,革命尚未成功,还不能倒下······(cry,hopeless······)
如果单单是只经营一种pizza是可以这么写的,然鹅单单是一种显然是不够的,人都是喜新厌旧的嘛,面向对象也是这样,因为一个对象不可能满足顾客欲望的所有需求,所以要弄出多些花样,轮流去满足顾客才能维持这段供需关系。而且,作为生意人为了追求利益最大化肯定会拓展业务,增加产量,直到利润最大化,原理祥略。所以店长又增加了两种pizza模型——cheesepizza和clampizza。继续按照上面那样写也是可以的,加两段代码就可以了,可是此时的main()h函数就需要选择是哪种类型的pizza了。毕竟三个不算多,但如果数量增加到10个呢?代码太富态了!在获取输入方面问题其实是不大的。代码如下但千万别这么写!
1 class seafoodpizza: 2 3 def prepare(self): 4 return 'prepare seafood_pizza' 5 6 def bake(self): 7 return 'bake seafood_pizza' 8 9 def cut(self): 10 return 'cut seafood_pizza' 11 12 def box(self): 13 return 'box seafood_pizza' 14 15 def orderpizza(self): 16 print(self.prepare()) 17 print(self.bake()) 18 print(self.cut()) 19 print(self.box()) 20 21 22 class cheesepizza: 23 24 def prepare(self): 25 return 'prepare cheese_pizza' 26 27 def bake(self): 28 return 'bake cheese_pizza' 29 30 def cut(self): 31 return 'cut cheese_pizza' 32 33 def box(self): 34 return 'box cheese_pizza' 35 36 def orderpizza(self): 37 print(self.prepare()) 38 print(self.bake()) 39 print(self.cut()) 40 print(self.box()) 41 42 43 class clampizza: 44 45 def prepare(self): 46 return 'prepare clam_pizza' 47 48 def bake(self): 49 return 'bake clam_pizza' 50 51 def cut(self): 52 return 'cut clam_pizza' 53 54 def box(self): 55 return 'box clam_pizza' 56 57 def orderpizza(self): 58 print(self.prepare()) 59 print(self.bake()) 60 print(self.cut()) 61 print(self.box()) 62 63 64 def main(): 65 pizza = input('enter the pizza you want from the options seafood cheese clam or no?\n') # 放在循环外便于返回 66 while true: 67 if pizza == 'seafood': 68 pizza = seafoodpizza() 69 pizza.orderpizza() 70 print('seafood_pizza completed') 71 pizza = input('you have order seafood_pizza, anything else? enter seafood cheese clam or no?\n ') 72 73 elif pizza == 'cheese': 74 pizza = cheesepizza() 75 pizza.orderpizza() 76 print('cheese_pizza completed') 77 pizza = input('you have order cheese_pizza, anything else? enter seafood cheese clam or no?\n ') 78 79 elif pizza == 'clam': 80 pizza = clampizza() 81 pizza.orderpizza() 82 print('clam_pizza completed') 83 pizza = input('you have order clam_pizza, anything else? enter seafood cheese clam or no?\n ') 84 85 elif pizza == 'no': 86 print('bye') 87 return 88 else: 89 pizza = input('enter the pizza you want from the options seafood cheese clam or no?\n') 90 91 92 if __name__ == '__main__': 93 main()
那么如何写的简短点呢?很快,我们发现,虽然pizza不一样,但每种pizza的orderpizza的形式是一样的,所有有什么办法让它独立出来以达一劳永逸呢?因此我们要处理不同pizza的订单,那么我们应该创建一个专门处理订单的类,orderpizza将作为它的方法被调用,那么如何创建这个类以兼容不同的订单呢?无论这个类取啥名,只要它能够实现方法调用即可,但是如古装剧非常讲究名正言顺一样,起名适宜也是很重要的。例如:书上起的名字就是pizzastore。
既然pizzastore要能够处理不同的订单,那么它的orderpizza方法就需要引入不同的类型判断,而类型可以通过特殊方法__int__初始化类型参数?代码如下,但请别这样搞。
1 class seafoodpizza: 2 3 def prepare(self): 4 return 'prepare seafood_pizza' 5 6 def bake(self): 7 return 'bake seafood_pizza' 8 9 def cut(self): 10 return 'cut seafood_pizza' 11 12 def box(self): 13 return 'box seafood_pizza' 14 15 16 class cheesepizza: 17 18 def prepare(self): 19 return 'prepare cheese_pizza' 20 21 def bake(self): 22 return 'bake cheese_pizza' 23 24 def cut(self): 25 return 'cut cheese_pizza' 26 27 def box(self): 28 return 'box cheese_pizza' 29 30 31 class clampizza: 32 33 def prepare(self): 34 return 'prepare clam_pizza' 35 36 def bake(self): 37 return 'bake clam_pizza' 38 39 def cut(self): 40 return 'cut clam_pizza' 41 42 def box(self): 43 return 'box clam_pizza' 44 45 46 class pizzastore: 47 48 def __init__(self, type): # 初始化类型参数type 49 self.type = type # 赋值属性self.type为参数type 50 51 def orderpizza(self): 52 if self.type == 'seafood': # 引入参数判断 53 self.pizza = seafoodpizza() 54 elif self.type == 'cheese': 55 self.pizza = cheesepizza() 56 elif self.type == 'clam': 57 self.pizza = clampizza() 58 59 print(self.pizza.prepare()) # 类型方法调用 60 print(self.pizza.bake()) 61 print(self.pizza.cut()) 62 print(self.pizza.box()) 63 print(self.type + '_pizza completed!') 64 65 66 def main(): 67 pizza = input('enter the pizza you want from the options seafood cheese clam or no?\n') # 放在循环外便于返回 68 while true: 69 if pizza in ['seafood', 'cheese', 'clam']: # 如果列表太长只能上数据库啦 70 pizza = pizzastore(pizza) 71 pizza.orderpizza() 72 pizza = input('you have order one pizza anything else? seafood cheese clam or no?\n') 73 74 elif pizza == 'no': 75 print('bye') 76 return 77 78 else: 79 pizza = input('enter the pizza you want from the options seafood cheese clam or no?\n') 80 81 82 if __name__ == '__main__': 83 main()
不过见不得好到哪里去!如何进一步编呢?很快我们又发现了上述代码中orderpizza函数仍然是不变的,而类型判断那部分是随时有可能变化的,能不能让pizzastore中变化的代码抽出去免得老是要添加来添加去呢?为了廉价付人工,把它交给制造工厂吧!这就是下面要是的简单工厂模式!
工厂模式介绍
在介绍简单工厂前,先看下工厂模式,书上是这么写的,在面向对象编程中,术语“工厂”表示一个负责创建其他类型对象的类。通常,这个类有一个对象以及多个和对象相关的多个方法,至于为什么要创建这样的一个类来创建对象呢?因为从上面的代码也可以看到,我们可以在main()函数里面实例化。那为什么还要这么做呢?当然因为这样做是由好吃的。
- 松耦合,即对象的创建可以独立于类的实现
- 客户端无需了解创建对象的类,也可以使用它来创建对象
- 轻松地在工厂中添加其他类来创建其他类型的对象,而这无需更改客户端代码,客户端只需要传递一个参数即可。
- 工厂可以重用现有对象。但是客户端则总是创建一个新的对象。
这些优点不要说没实践过,就算亲自实践过也可能不知道它说的啥,比如:按照上面的例子客户端也只需提供一个参数啊!不管了,还是继续往下写吧,人生苦短······
简单工厂模式
很多介绍都说简单工厂不是一种模式,无论如何,笔者只想看看它的特征,嗯,笔者看到了,书上是这么写的:允许接口创建对象,但不会暴露对象的创建逻辑!参考前面的代码,如果要创一个“简单工厂”,就创一个simpizzafactory,再定义一个create_pizza函数,然后进行类型判断,然后在进行类型创建。在“工厂”里创建了类型对象,自然在pizzastore类里面进可以不用再做这么多工作了,但是,要把工厂创建的对象导进来,如何导进来呢?对啦!寄望于魔术方法__init__!将“简单工厂”作为参数传递给pizzastore来进行初始化,这样就可以将类型作为参数传递给orderpizza了。代码如下:
1 class seafoodpizza: 2 3 def prepare(self): 4 return 'prepare seafood_pizza' 5 6 def bake(self): 7 return 'bake seafood_pizza' 8 9 def cut(self): 10 return 'cut seafood_pizza' 11 12 def box(self): 13 return 'box seafood_pizza' 14 15 16 class cheesepizza: 17 18 def prepare(self): 19 return 'prepare cheese_pizza' 20 21 def bake(self): 22 return 'bake cheese_pizza' 23 24 def cut(self): 25 return 'cut cheese_pizza' 26 27 def box(self): 28 return 'box cheese_pizza' 29 30 31 class clampizza: 32 33 def prepare(self): 34 return 'prepare clam_pizza' 35 36 def bake(self): 37 return 'bake clam_pizza' 38 39 def cut(self): 40 return 'cut clam_pizza' 41 42 def box(self): 43 return 'box clam_pizza' 44 45 46 class simpizzafactory: 47 48 def creat_pizza(self, type): 49 pizza = none 50 51 if type == 'seafood': 52 pizza = seafoodpizza() 53 elif type == 'cheese': 54 pizza = cheesepizza() 55 elif type == 'clam': 56 pizza = clampizza() 57 return pizza 58 59 60 class pizzastore: 61 62 def __init__(self, factory): 63 self.factory = factory 64 65 def orderpizza(self, type): 66 pizza = self.factory.creat_pizza(type) 67 print(pizza.prepare()) 68 print(pizza.bake()) 69 print(pizza.cut()) 70 print(pizza.box()) 71 print(type + '_pizza completed!') 72 73 74 def main(): 75 type = input('input the type of pizza you want from the options seafood cheese clam or no?\n') 76 while true: 77 if type in ['seafood', 'cheese', 'clam']: # 如果列表太长只能上数据库啦 78 pizza = pizzastore(simpizzafactory()) 79 pizza.orderpizza(type) 80 type = input('you have order one pizza anything else? seafood cheese clam or no?\n') 81 82 elif type == 'no': 83 print('bye') 84 return 85 86 else: 87 type = input('input the pizza you want from the options seafood cheese clam or no?\n') 88 89 90 if __name__ == '__main__': 91 main()
好像也不见得什么啊,不过还是实现了将几乎不用改变的代码和经常需要变动的代码分离开,还是继续往下写吧,人生······
工厂方法模式
一个“简单工厂”类实现了类型的实例化,无论有多少种pizza要做我都扔给工厂去做,问题到此似乎该告一段落了,然而人的欲望是不可能有尽头的,该来的还是来了,店长决定在全国都开起了分店。现在要怎么编呢?比如北京一个店,上海开一个······
如果按照简单工厂前面的想法去写,应该也是可以的。但是通过不同方法的比较,我们已经认为简单工厂的方法目前是比较好的一种方式。所以这里就直接用简单工厂的方法去开分店了。
现在制造pizza的类型要重新创建了,因为多了一个地域变量使得制造pizza的方法也各有不同,这些代码自然是不能省的,那么,工厂方法现在又要如何去处理(创建类型),自然很快就带来了一个问题:再不能仅仅依靠类似前面的类型判断去创建对象,因为不同分店的同种pizza是不同的!例如:北京分店的seafood_pizza和上海分店的seafood_pizza做法是有差别的!例如人们经常说的某酒必须要它当地的水才能酿成那种味道云云···,所以,在工厂还需确定是那种风格的pizza——北京风格还是上海风格?,再确定是那种口味的pizza,然后才能准确的调用相应的pizza种类。为此,我们可以通过创建不同种类的简单工厂来创建pizza类型。无论如何先帖代码,代码如下:
1 class beijingseafoodpizza: 2 3 def prepare(self): 4 return 'prepare beijing_seafood_pizza' 5 6 def bake(self): 7 return 'bake beijing_seafood_pizza' 8 9 def cut(self): 10 return 'cut beijing_seafood_pizza' 11 12 def box(self): 13 return 'box beijing_seafood_pizza' 14 15 16 class beijingcheesepizza: 17 18 def prepare(self): 19 return 'prepare beijing_cheese_pizza' 20 21 def bake(self): 22 return 'bake beijing_cheese_pizza' 23 24 def cut(self): 25 return 'cut beijing_cheese_pizza' 26 27 def box(self): 28 return 'box beijing_cheese_pizza' 29 30 31 class beijingclampizza: 32 33 def prepare(self): 34 return 'prepare beijing_clam_pizza' 35 36 def bake(self): 37 return 'bake beijing_clam_pizza' 38 39 def cut(self): 40 return 'cut beijing_clam_pizza' 41 42 def box(self): 43 return 'box beijing_clam_pizza' 44 45 class shanghaiseafoodpizza: 46 47 def prepare(self): 48 return 'prepare shanghai_seafood_pizza' 49 50 def bake(self): 51 return 'bake shanghai_seafood_pizza' 52 53 def cut(self): 54 return 'cut shanghai_seafood_pizza' 55 56 def box(self): 57 return 'box shanghai_seafood_pizza' 58 59 60 class shanghaicheesepizza: 61 62 def prepare(self): 63 return 'prepare shanghai_cheese_pizza' 64 65 def bake(self): 66 return 'bake shanghai_cheese_pizza' 67 68 def cut(self): 69 return 'cut shanghai_cheese_pizza' 70 71 def box(self): 72 return 'box shanghai_cheese_pizza' 73 74 75 class shanghaiclampizza: 76 77 def prepare(self): 78 return 'prepare shanghai_clam_pizza' 79 80 def bake(self): 81 return 'bake shanghai_clam_pizza' 82 83 def cut(self): 84 return 'cut shanghai_clam_pizza' 85 86 def box(self): 87 return 'box shanghai_clam_pizza' 88 89 90 class beijingfactory: 91 92 def creat_pizza(self, type): 93 pizza = none 94 95 if type == 'seafood': 96 pizza = beijingseafoodpizza() 97 elif type == 'cheese': 98 pizza = beijingcheesepizza() 99 elif type == 'clam': 100 pizza = beijingclampizza() 101 return pizza 102 103 104 class shanghaifactory: 105 106 def creat_pizza(self, type): 107 pizza = none 108 109 if type == 'seafood': 110 pizza = shanghaiseafoodpizza() 111 elif type == 'cheese': 112 pizza = shanghaicheesepizza() 113 elif type == 'clam': 114 pizza = shanghaiclampizza() 115 return pizza 116 117 118 class pizzastore: 119 120 def __init__(self, factory): 121 self.factory = factory 122 123 def orderpizza(self, type): 124 pizza = self.factory.creat_pizza(type) 125 print(pizza.prepare()) 126 print(pizza.bake()) 127 print(pizza.cut()) 128 print(pizza.box()) 129 print(type + '_pizza completed!') 130 131 132 def main(): 133 region = input('input the region of pizza of you want bejing shanghai or no\n') 134 if region == 'no': 135 print('bye') 136 return 137 type = input('input the type of pizza you want from the options seafood cheese clam or no?\n') 138 139 while true: 140 141 if region == 'beijing' and type in ['seafood', 'cheese', 'clam']: 142 factory = beijingfactory() 143 pizza = pizzastore(factory) 144 pizza.orderpizza(type) 145 region = input('you have order one pizza anything else? bejing shanghai or no\n') 146 if region == 'no': 147 print('bye') 148 return 149 type = input('you have order one pizza anything else? seafood cheese clam or no?\n') 150 151 elif region == 'shanghai' and type in ['seafood', 'cheese', 'clam']: 152 factory = shanghaifactory() 153 pizza = pizzastore(factory) 154 pizza.orderpizza(type) 155 region = input('you have order one pizza anything else? bejing shanghai or no\n') 156 if region == 'no': 157 print('bye') 158 return 159 type = input('you have order one pizza anything else? seafood cheese clam or no?\n') 160 161 else: 162 region = input('input the region of pizza of you want bejing shanghai or no\n') 163 164 165 if __name__ == '__main__': 166 main()
这个代码又笨又长,但笔者认为,只要每种pizza的制作方法不一样,有多少种pizza,就有多少段pizza代码,尽管代码很长,当然可以借助from ...import...来缩短代码,但总的代码数应当不能减少,当然也可以用继承,但是不够简单粗暴。其实创建简单工厂的时候也可以加入一个额外的参数变量——region,那样的判断和主函数的逻辑是一样的。另外,当pizza种类越来越多的时候,交互的内容也会越来越多,所以这里也可以定义一个help函数去简洁点处理。如此看来,简单工厂也是可以实现的,但是,也看到了这样的工厂在种类多起来的时候,工厂专业化程度越来越高,变动成本(重新调整逻辑的时间)越来越高!
这时候怎么办呢?书上说要仰赖工厂方法,先看看工厂方法的特点:
- 我们定义了一个接口来创建,但是工厂本身并不负责创建对象,而是将这个任务交由子类来完成,即由子类决定了要实例化哪些类
- 工厂方法的创建是通过继承而不是通过实例化来完成的
- 工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某些类型的对象(就像在简单工厂方法中的那样)
先看下代码:
1 class beijingseafoodpizza: 2 3 def prepare(self): 4 return 'prepare beijing_seafood_pizza' 5 6 def bake(self): 7 return 'bake beijing_seafood_pizza' 8 9 def cut(self): 10 return 'cut beijing_seafood_pizza' 11 12 def box(self): 13 return 'box beijing_seafood_pizza' 14 15 16 class beijingcheesepizza: 17 18 def prepare(self): 19 return 'prepare beijing_cheese_pizza' 20 21 def bake(self): 22 return 'bake beijing_cheese_pizza' 23 24 def cut(self): 25 return 'cut beijing_cheese_pizza' 26 27 def box(self): 28 return 'box beijing_cheese_pizza' 29 30 31 class beijingclampizza: 32 33 def prepare(self): 34 return 'prepare beijing_clam_pizza' 35 36 def bake(self): 37 return 'bake beijing_clam_pizza' 38 39 def cut(self): 40 return 'cut beijing_clam_pizza' 41 42 def box(self): 43 return 'box beijing_clam_pizza' 44 45 46 class shanghaiseafoodpizza: 47 48 def prepare(self): 49 return 'prepare shanghai_seafood_pizza' 50 51 def bake(self): 52 return 'bake shanghai_seafood_pizza' 53 54 def cut(self): 55 return 'cut shanghai_seafood_pizza' 56 57 def box(self): 58 return 'box shanghai_seafood_pizza' 59 60 61 class shanghaicheesepizza: 62 63 def prepare(self): 64 return 'prepare shanghai_cheese_pizza' 65 66 def bake(self): 67 return 'bake shanghai_cheese_pizza' 68 69 def cut(self): 70 return 'cut shanghai_cheese_pizza' 71 72 def box(self): 73 return 'box shanghai_cheese_pizza' 74 75 76 class shanghaiclampizza: 77 78 def prepare(self): 79 return 'prepare shanghai_clam_pizza' 80 81 def bake(self): 82 return 'bake shanghai_clam_pizza' 83 84 def cut(self): 85 return 'cut shanghai_clam_pizza' 86 87 def box(self): 88 return 'box shanghai_clam_pizza' 89 90 91 class pizzastore: 92 93 def create_pizza(self, type): # 抽象方法,由子类去实现 94 raise notimplementederror 95 96 def orderpizza(self, type): 97 pizza = self.create_pizza(type) 98 print(pizza.prepare()) 99 print(pizza.bake()) 100 print(pizza.cut()) 101 print(pizza.box()) 102 print(type + '_pizza completed!') 103 104 105 class beijingpizzastore(pizzastore): 106 def create_pizza(self, pizza_type): 107 pizzas = dict(cheese=beijingcheesepizza, clam=beijingclampizza, seafood=beijingseafoodpizza) 108 return pizzas[pizza_type]() 109 110 111 class shanghaipizzastore(pizzastore): 112 def create_pizza(self, pizza_type): 113 pizzas = dict(cheese=shanghaicheesepizza, clam=shanghaiclampizza, seafood=shanghaiseafoodpizza) 114 return pizzas[pizza_type]() 115 116 117 def main(): 118 region = input('input the region of pizza of you want bejing shanghai or no\n') 119 if region == 'no': 120 print('bye') 121 return 122 type = input('input the type of pizza you want from the options seafood cheese clam or no?\n') 123 124 while true: 125 126 if region == 'beijing' and type in ['seafood', 'cheese', 'clam']: 127 store = beijingpizzastore() 128 store.orderpizza(type) 129 region = input('you have order one pizza anything else? bejing shanghai or no\n') 130 if region == 'no': 131 print('bye') 132 return 133 type = input('you have order one pizza anything else? seafood cheese clam or no?\n') 134 135 elif region == 'shanghai' and type in ['seafood', 'cheese', 'clam']: 136 store = shanghaipizzastore() 137 store.orderpizza(type) 138 region = input('you have order one pizza anything else? bejing shanghai or no\n') 139 if region == 'no': 140 print('bye') 141 return 142 type = input('you have order one pizza anything else? seafood cheese clam or no?\n') 143 144 else: 145 region = input('input the region of pizza of you want bejing shanghai or no\n') 146 147 148 if __name__ == '__main__': 149 main()
可以看到,相对来说,这里的代码貌似简洁了一点。这其中抛弃了简单工厂,从而将create_pizza函数搬到pizza_store工厂下面,并用抽象类的方法重新定义,然后让pizza_store工厂的子类beijingpizzastore和shanghaipizzastore分店分别取实现自己的create_pizza,这也是工厂方法常用的方法。代码太长主要还是是piazza的种类的代码但必须要有,而交互随着pizza种类而也变得复杂。工厂方法的优点书上所说如下:
- 它具有更大的灵活性,使得代码更加通用,因为它不是单纯地实例化某个类。这样实现哪些类取决于接口(product),而不是concretecreator类。
- 松耦合,因为创建对象的代码与使用它的代码是分开的。客户端无需关心传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。
抽象工厂
抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体的类。工厂方法将创建实例的任务委托给了子类,而抽象工厂方法的目标是创建一系列相关对象。代码和书本差不多,所以大家看书即可,可能前面啰嗦太甚,这节草草了事凑下整,哈哈,看起来代码比上面的短,但仿照来写应该不会比上面的短很多,代码粘贴自于这篇博客:
:
1 from abc import abcmeta, abstractmethod 2 3 4 # abstractfactory 5 class pizzafactory(metaclass=abcmeta): 6 @abstractmethod 7 def createvegpizza(self): 8 pass 9 10 @abstractmethod 11 def createnonvegpizza(self): 12 pass 13 14 15 # concretefactory 16 class indianpizzafactory(pizzafactory): 17 def createvegpizza(self): 18 return deluxveggiepizza() 19 20 def createnonvegpizza(self): 21 return chickenpizza() 22 23 24 # concretefactory 25 class uspizzafactory(pizzafactory): 26 def createvegpizza(self): 27 return mexicanvegpizza() 28 29 def createnonvegpizza(self): 30 return hampizza() 31 32 33 # 进一步定义 abstractproducts: 34 # abstractproduct 35 class vegpizza(metaclass=abcmeta): 36 @abstractmethod 37 def prepare(self, vegpizza): # 定义自己的方法 38 pass 39 40 41 # anotherabstractproduct 42 class nonvegpizza(metaclass=abcmeta): 43 @abstractmethod 44 def serve(self, vegpizza): # 定义自己的方法 45 pass 46 47 48 # 为每个abstractproducts定义concreteproducts,创建deluxveggiepizza和mexicanvegpizza: 49 class deluxveggiepizza(vegpizza): # concreteproducts1 50 def prepare(self): 51 print('prepare:', type(self).__name__) 52 53 54 # 定义anotherconcreteproduct: 55 class mexicanvegpizza(vegpizza): # concreteproducts2 56 def prepare(self): 57 print('prepare:', type(self).__name__) 58 59 60 # 定义chickenpizza和hampizza,分别代表anotherconcreteproducts1和anotherconcreteproducts2: 61 class chickenpizza(nonvegpizza): # anotherconcreteproducts1 62 def serve(self, vegpizza): 63 print(type(self).__name__, ' is served with chicken on ', type(vegpizza).__name__) 64 65 66 class hampizza(nonvegpizza): 67 def serve(self, vegpizza): 68 print(type(self).__name__, ' is served with ham on ', type(vegpizza).__name__) 69 70 71 # 当最终用户来到pizzastore并要一份美式非素食披萨的时候,uspizzafactory负责准备素食, 72 # 然后在上面加上火腿,马上就变成非素食披萨了: 73 class pizzastore: 74 def __init__(self): 75 pass 76 77 def makepizzas(self): 78 for factory in [indianpizzafactory(), uspizzafactory()]: 79 self.factory = factory 80 self.nonvegpizza = self.factory.createnonvegpizza() 81 self.vegpizza = self.factory.createvegpizza() 82 self.vegpizza.prepare() 83 self.nonvegpizza.serve(self.vegpizza) 84 85 86 if __name__ == '__main__': 87 pizza = pizzastore() 88 pizza.makepizzas()
至此,笔者的笨拙想法卒。
下一篇: 爆囧,一家老小笑事不少!