OOP设计简介

继承:‘是一个’的关系

假设我们决定开一家餐厅。我们需要做的其中一件事就是聘请员工为顾客服务、准备食物,等等。工程师是核心,我们决定创造一个做饭机器人,但是为了符合逻辑,我们也决定把机器人做成有薪水的功能齐全的员工。

饭店团队可以通过文件employees.py中的四个类来定义。最通用的类Employee提供共同行为,例如,加薪(giveRaise)和打印(__str__)。员工有两种,所以Employee有两个子类:Chef和Server。这两个子类都会覆盖继承的work方法来打印更具体的信息。最后,我们的机器人是由更具体的类来模拟:Robot是一种Chef,也是一种Employee。以OOP术语来看,我们称这些关系为“是一个”(is-a)链接:机器人是一个主厨,而主厨是一个员工。以下是employees.py文件。

<code> 

class

Employee

:

def

__init__

(

self

,name,salary=

0

)

:

self

.name=name

self

.salary=salary

def

giveRaise

(

self

,percent)

:

self

.salary=

self

.salary*(

1

+percent)

def

work

(

self

)

: print(

self

.name,

'does stuff'

)

def

__str__

(

self

)

:

return

'Employee:%s,%d'

%(self.name,self.salary)

class

Chef

(

Employee

):

def

__init__

(

self

,name)

: Employee.__init_

_

(

self

,name,

50000

)

def

work

(

self

)

: print(

self

.name,

'makes food'

)

class

Server

(

Employee

):

def

__init__

(

self

,name)

: Employee.__init_

_

(

self

,name,

40000

)

def

work

(

self

)

: print(

self

.name,

'does service'

)

class

Robot

(

Chef

):

def

__init__

(

self

,name)

: Chef.__init_

_

(

self

,name)

def

work

(

self

)

: print(

self

.name,

'Robot is working!'

)

if

__name_

_

==

'__main__'

:

for

Kclass

in

(Employee,Chef,Server,Robot): obj=Kclass(Kclass.__name_

_

) obj.work() Employee does stuff Chef makes food Server does service Robot Robot is working!/<code>

组合:‘有一个’的关系

既然我们已经有了员工,就把他们放到饭店,开始忙吧。我们的店是一个组合对象,有个烤炉,也有服务生和主厨这些员工。当顾客来店下单时,店里的组件就会开始行动:服务生接下订单,主厨制作比萨,等等。下面的例子(文件foodshop.py)模拟了这个场景中所有的对象和关系。

<code>

class

Customer

:

def

__init__

(

self

,name,food_list)

:

self

.name=name

self

.food_list=food_list

def

order

(

self

,server)

: print(

'%s is serving for %s,the food he order is %s'

%(server.name,self.name,str(self.food_list)

))

def

pay

(

self

,server)

: print(

'%s has paid to %s'

%(self.name,server.name)

)

class

Oven

:

def

bake

(

self

)

: print(

'The oven is baking!'

)

class

Foodshop

:

def

__init__

(

self

)

:

self

.server=Server(

'John'

)

self

.chef=Robot(

'Bob'

)

self

.oven=Oven()

def

Order

(

self

,name)

: customer=Customer(name,[

'tea'

,

'soup'

]) customer.order(

self

.server)

self

.chef.work()

self

.oven.bake() customer.pay(

self

.server)

if

__name_

_

==

'__main__'

: aaa=Foodshop() aaa.Order(

'shunge'

) John is serving

for

shunge,the food he order is [

'tea'

,

'soup'

] Bob Robot is working! The oven is baking! shunge has paid to John/<code>

OOP与委托

面向对象时常会谈到所谓的委托(delegation),通常就是指控制器对象内嵌其他对象,而把运算请求传给那些对象。控制器负责管理工作,例如,记录存取等。在Python中,委托通常是以__getattr__方法实现的,因为这个方法会拦截对不存在属性的读取,包装类(有时称为代理类)可以使用__getattr__把任意读取转发给被包装的对象。包装类包有被包装对象的接口,而且自己也可以增加其他运算。例:跟踪打印消息

<code>

class

trace

:

def

__init__

(

self

,obj)

:

self

.obj=obj

def

__getattr__

(

self

,attrname)

: print(

'Trace:'

,attrname)

return

getattr(

self

.obj,attrname) x=trace([

1

,

2

,

3

,

4

,

5

]) x.append(

5

) output:

Trace:

append/<code>

类的伪私有属性

Python程序员用一个单个的下划线来编写内部名称(例如,_X),这只是一个非正式的惯例,让你知道这是一个不应该修改的名字(它对Python自身来说没有什么意义)。

但更通用的方法是变量名前面加上两个下划线,比如Person类中的__salary,会自动扩展为_Person__salary,这样就避免了和其他类所创建的类似变量名冲突。

<code> 

class

Person

:

def

__init__

(self,name)

:

self.__name=name a=Person(

'shunge'

) print(a.__dict__) a.__name=

'shun'

print(a.__name,a._Person__name) output:{

'_Person__name'

:

'shunge'

} shun shunge /<code>


分享到:


相關文章: