第五章:5.2面向对象-绑定方法和非绑定方法| 内置方法 |元类
1. 类内部定义的函数
绑定方法与非绑定方法
在类内部定义的函数,分为两大类:
一:绑定方法:绑定给谁,就应该由谁来调用,谁来调用就会把调用者当作第一个参数自动传入
绑定到对象的方法:在类内定义的没有被任何装饰器修饰的,会把自己当做第一个参数传进去;
绑定到类的方法:在类内定义的被装饰器classmethod修饰的方法。
二:非绑定方法:没有自动传值这么一说了,就类中定义的一个普通工具,对象和类都可以使用调用
非绑定方法:不与类或者对象绑定;
#####绑定到对象
class Foo:
def __init__(self,name):
self.name = name
def tell(self): #绑定到对象的方法;类内部定义的函数就是给对象使用的
print('名字是%s'%self.name)
f = Foo('egon')
#print(Foo.tell) #<function Foo.tell at 0x000000000299CB70> 类访问自己内部函数属性的时候,它就是一个普通函数,没有自动传值一说
#Foo.tell(f) #名字是egon 类非要用,就要给它传值
# print(f.tell) #<bound method Foo.tell of <__main__.Foo object at 0x00000000027BF630>> 绑定方法指向类的那个函数,跟类使用的是一个功能。
f.tell() #名字是egon 绑定给谁就由谁来调用,就会把调用者当做第一个参数自动传进去;
#####绑定到类
class Foo:
def __init__(self,name):
self.name = name
def tell(self):
print('名字是%s'%self.name)
@classmethod ###绑定到类的方法
def func(cls): #绑定到类,把类当做第一个参数传进去;cls=Foo
print(cls)
print(Foo.func) #<bound method Foo.func of <class '__main__.Foo'>> 加了装饰器后,定义成绑定到类的方法而不是函数了
Foo.func() #<class '__main__.Foo'>
######非绑定方法,没有自动传值了
class Foo:
def __init__(self,name):
self.name = name
def tell(self):
print('名字是%s'%self.name)
@classmethod
def func(cls): #绑定到类,把类当做第一个参数传进去;
print(cls)
@staticmethod #这才被认为一个真正意义上的函数,没有自动传值了。非绑定方法加个@staticmethod
def func1(x,y):
print(x+y)
f = Foo('egon')
f.func() #<class '__main__.Foo'>
print(Foo.func1) #<function Foo.func1 at 0x000000000296CC80> 类 都是普通函数
print(f.func1) #<function Foo.func1 at 0x000000000296CC80> 对象 普通函数
Foo.func1(1,2) #3 类来调用
f.func1(2,4) #6 对象来调用
在类内部定义的函数分为两大类:绑定方法和非绑定方法(就是普通函数)。
使用场景
根据函数体的逻辑想传什么参数
class People: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell_info(self): #绑定到对象的方法 print('Name:%s Age:%s Sex:%s'%(self.name,self.age,self.sex)) p = People('egon',18,'male') #绑定给对象,就应该由对象来调用,自动将对象本身当做第一个参数传入 p.tell_info() #tell_info(p) # Name:egon Age:18 Sex:male
import settings #写一个配置文件 name = 'alex' age = 18 sex = male class People: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell_info(self): #绑定到对象的方法 print('Name:%s Age:%s Sex:%s'%(self.name,self.age,self.sex)) @classmethod def from_conf(cls): #不能写死,需要写个参数把类传进去 obj = cls( settings.name, settings.age, settings.sex ) return obj #绑定给类,就应该由类来调用,自动将类本身当做第一个参数传入 p = People.from_conf() #本质上就是from_conf(People) #从配置文件里边读取配置进行实例化 p.tell_info() #Name:alex Age:18 Sex:male
import settings import hashlib import time class People: def __init__(self,name,age,sex): self.id = self.creat_id() #需要传参数就传 self.name = name self.age = age self.sex = sex def tell_info(self): #绑定到对象的方法 print('Name:%s Age:%s Sex:%s'%(self.name,self.age,self.sex)) @classmethod def from_conf(cls): obj = cls( settings.name, settings.age, settings.sex ) return obj #非绑定方法,不与类或者对象绑定,谁都可以调用,没有自动传值一说 @staticmethod def creat_id(): #不依赖类和对象传入参数 m=hashlib.md5(str(time.time()).encode('utf-8')) return m.hexdigest() p1=People('egon1',18,'male') p2=People('egon2',28,'male') p3=People('egon3',38,'male') print(p1.create_id()) #66c0399486670e0faaab1324e98b33b0 print(p2.id) #66c0399486670e0faaab1324e98b33b0 print(p3.id) #66c0399486670e0faaab1324e98b33b0
2. 反射
通过字符串来映射到一个对象的属性
class People:
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
obj=People('egon',18)
# print(obj.name) #obj.__dict__['name'] #.后面是个属性,而不是字符串;用户通过字符串来映射到一个对象的属性身上
# print(obj.talk) #<bound method People.talk of <__main__.People object at 0x00000000027DFB00>>
# choice=input('>>: ') #choice='name'
# print(obj.choice) #会报错 print(obj.'name')
#判断有没有这个属性
print(hasattr(obj,'name')) #True obj.name #obj.__dict__['name']
print(hasattr(obj,'talk')) #True obj.talk
#拿到对象的属性 ,没有就报错
print(getattr(obj,'name')) # egon
print(getattr(obj,'namexx',None)) # None
print(gatattr(obj,'talk')) #<bound method People.talk of <__main__.People object at 0x0000000002961F28>>
#修改 或新增
setattr(obj,'sex','male') #obj.sex = 'male'
print(obj.sex) # male
#删除
delattr(obj,'age') # del obj.age
print(obj.__dict__) # {'name': 'egon', 'sex': 'male'}
#类同样适用以上方法
print(getattr(People,'country')) #People.country #China
####反射的应用:
class Service:
def run(self):
while True:
inp=input('>>: ').strip() #cmd='get a.txt'
cmds=inp.split() #cmds=['get','a.txt']
# print(cmds)
if hasattr(self,cmds[0]): #判断有没有get这个方法
func=getattr(self,cmds[0]) #拿到它
func(cmds) #执行
def get(self,cmds):
print('get.......',cmds)
def put(self,cmds):
print('put.......',cmds)
obj=Service()
obj.run()
3. 内置方法
http://www.cnblogs.com/linhaifeng/articles/6204014.html
isinstance(obj,cls)检查是否obj是否是类 cls 的对象,判断谁是谁的实例;
issubclass(sub, super)检查sub类是否是 super 类的派生类
只要是__开头__结尾的方法都不要直接去用,python会自动调用的,什么情况下会触发呢?
####item系列 #把对象模拟成像字典样
###获取
class Foo: #Dict
def __init__(self,name):
self.name=name
def __getitem__(self, item): #要知道item获取的什么值 #item='name',把name传进去;我通过字符串怎么访问属性呢,可以用反射,也可以self.__dict__(item)
print('getitem...')
print(item)
return self.__dict__.get(item) #这样就取到值了;通过字典的key取它的value ##有就取值,没有就不会报错了
def __setitem__(self, key, value):
print('setitem...')
print(key,value)
self.__dict__[key]=value
def __delitem__(self, key):
print('delitem...')
print(key)
del self.__dict__[key]
obj=Foo('egon') ##把obj模拟成字典的样子
print(obj.__dict__) #{'name': 'egon'}
###查看属性
#obj.属性名 #原来是这样获取的
#obj['name'] #打印出:getitem... name obj.name想要完成这样一个取值,应该让那个方法有个返回值;按照这种形式一打开它就会触发__getitem__来取值
#print(obj['name'] #打印出:getitem... name egon
print(obj['namexx']) #打印出:getitem... namexx None obj.name
class Foo: #Dict
def __init__(self,name):
self.name=name
def __getitem__(self, item): #要知道item获取的什么值 #item='name'
print('getitem...')
print(item)
return self.__dict__.get(item) #通过字典的key取它的value #有就取值,没有就不会报错了
def __setitem__(self, key, value): #value就是要设置的值
#print('setitem...')
#print(key,value)
self.__dict__[key]=value #这样就完成了真正的设置,上边两步就可以去掉了
def __delitem__(self, key):
print('delitem...')
print(key)
del self.__dict__[key]
obj=Foo('egon')
#print(obj.__dict__)
#设置属性
#obj.sex = 'male'
obj['sex'] = 'male' #会触发__setitem__,并且打印key,value
print(obj.__dict__) #验证下,设置成功了 #{'name': 'egon', 'sex': 'male'}
print(obj.sex) #获取 male
class Foo: #Dict
def __init__(self,name):
self.name=name
def __getitem__(self, item): #要知道item获取的什么值 #item='name'
#print('getitem...')
#print(item)
return self.__dict__.get(item) #通过字典的key取它的value #有就取值,没有就不会报错了
def __setitem__(self, key, value):
#print('setitem...')
#print(key,value)
self.__dict__[key]=value #这样就完成了真正的设置,上边两步就可以去掉了
def __delitem__(self, key):
#print('delitem...')
#print(key)
del self.__dict__[key] ##完成真正的删除
obj=Foo('egon')
#print(obj.__dict__)
#查看属性
#obj.属性名 #原来是这样获取的
#obj['name'] #obj.name 想要完成这样一个取值,应该让那个方法有个返回值;一打开它就会触发__getitem__来取值
#print(obj['namexx']) #obj.name
#设置属性
#obj.sex = 'male'
# obj['sex'] = 'male' #会触发__setitem__,并且打印key,value
# print(obj.__dict__) #验证下,设置成功了
# print(obj.sex) #获取
#删除属性
#del obj.name
del obj['name']
print(obj.__dict__) #delitem... name {}
#########__str__方法:
# d=dict({'name':'egon'})
# print(isinstance(d,dict)) #True
# print(d) #{'name','egon'} #打印成有用的东西,而不是打印成内存地址
class People:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self): #__str__定义完之后,会在打印对象的时候会触发对象下的__str__方法,然后把返回字符串类型的结果打印出
print('====>str')
return '<name:%s,age:%s>' %(self.name,self.age) #要返回一个字符串类型
obj=People('egon',18)
print(obj) #打印出:====>str <name:egon,age:18> ;res=obj.__str__() #一打印的时候就会触发 obj.__str__()这个方法,把它的结果拿到打印
####__del__ 回收资源的
# f=open('settings.py')
# f.read()
# f.close() #回收操作系统的资源 ,执行它后f这个变量还存在
# print(f) #<_io.TextIOWrapper name='settings.py' mode='r' encoding='cp936'>
# f.read()
class Open:
def __init__(self,filename):
print('open file.......') #给操作系统发一个请求
self.filename=filename
def __del__(self): ##在对象被删除的时候会先触发这个方法的执行再删除。 程序运行完之后py会自动给你删对象,在删对象之前先触发这个方法的执行;
print('回收操作系统资源:self.close()') #py只会帮你回收对象本身,并不会给你回收对象相关的属性,这时候就可以写在这里了使用__del__
f=Open('settings.py') #它是一个变量,占应用程序的一个内存
#del f #del f 如果运行这一步是程序先运行打开文件,然后回收操作系统资源,最后执行完程序。 #同样也会触发它 f.__del__()
print('----main------') ##代表程序执行完了会自动触发del f的执行; 但遗留下操作系统的资源。
4. 元类介绍
exec:三个参数
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
g={
'x':1,
'y':2
}
l={}
#可以把exec看做一个函数,g,l是指定全局和局部作用域
exec("""
global x,m
x=10
m=100
z=3
""",g,l)
print(g)
print(l)
一切皆对象,对象可以怎么用?
- 都可以被引用,x=obj
- 都可以当作函数的参数传入
- 都可以当作函数的返回值
- 都可以当作容器类的元素,l=[func,time,obj,1]
##类也是对象,Foo=type(....) 看做type传了个值进去
class Foo:
pass
obj=Foo()
print(type(obj)) #<class '__main__.Foo'>
print(type(Foo)) #<class 'type'>
class Bar:
pass
print(type(Bar)) #查看类型 #<class 'type'>
##产生类的类称之为元类,默认所以用class定义的类,他们的元类是type
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
元类的实例化的结果为我们用class定义的类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象.
定义类的两种方式
#定义类的两种方式: #方式一:使用class关键字 class Chinese: #Chinese=type(...) country='China' def __init__(self,namem,age): self.name=namem self.age=age def talk(self): print('%s is talking' %self.name) # print(Chinese) obj=Chinese('egon',18) print(obj,obj.name,obj.age) #方式二:type 手动模拟class创建类的过程,将创建类的步骤拆分开,手动去创建。 #定义类的三要素:类名,类的基类们,类的名称空间 class_name='Chinese' #类名 class_bases=(object,) #继承的基类;类的父类 class_body=""" #类体 country='China' def __init__(self,namem,age): self.name=namem self.age=age def talk(self): print('%s is talking' %self.name) """ class_dic={} #放到字典里初始化为空 #应该把上边""" """里边类体的代码执行一下得到的结果放到一个字典里边; exec(class_body,globals(),class_dic) # print(class_dic) #{'country': 'China', '__init__': <function __init__ at 0x00000000003D3E18>, 'talk': <function talk at 0x0000000001F1CAE8>}
Chinese1=type(class_name,class_bases,class_dic) #得到一个元类 # print(Chinese1) #<class '__main__.Chinese'> obj1=Chinese1('egon',18) print(obj1,obj1.name,obj1.age) #<__main__.Chinese object at 0x00000000029619B0> egon 18
步骤一(先处理类体->名称空间):类体定义的名字都会存放于类的名称空间中(一个局部的名称空间),我们可以事先定义一个空字典,然后用exec去执行类体的代码(exec产生名称空间的过程与真正的class过程类似,只是后者会将__开头的属性变形),生成类的局部名称空间,即填充字典
步骤二:调用元类type(也可以自定义)来产生类Chinense
我们看到,type 接收三个参数:
- 第 1 个参数是字符串 ‘Foo’,表示类名
- 第 2 个参数是元组 (object, ),表示所有的父类
- 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
补充:若Foo类有继承,即class Foo(Bar):.... 则等同于type('Foo',(Bar,),{})
自定义元类控制类的创建
#一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的行为,工作流程是什么)
#自定义元类控制类的行为
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic): #可能覆盖父类;继承默认元类的一堆属性
if not class_name.istitle():
raise TypeError('类名的首字母必须大写') #会报错
print(class_dic) #{'__module__': '__main__', '__qualname__': 'Chinese', '__doc__': 'a\n 中文人的类 ##注释写上之后才有__doc__属性\n ', 'country': 'China', '__init__': <function Chinese.__init__ at 0x000000000296CB70>, 'talk': <function Chinese.talk at 0x000000000296CBF8>}
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dic) #你写__init__这个功能之前把父类的也重用了一遍
class Chinese(object,metaclass=Mymeta): #指定元类为Mymeta,这个类Chinese的创建行为就由你来控制了
'''a
中文人的类 ##注释写上之后才有__doc__属性
'''
country='China'
def __init__(self,namem,age):
self.name=namem
self.age=age
def talk(self):
print('%s is talking' %self.name)
# Chinese=Mymeta(class_name,class_bases,class_dic) #在实例化,必须要有个__init__方法;触发Mymeta实例化的过程就会触发__init__方法的执行
自定义元类控制类的实例化
#知识储备__call__方法 #让对象变成可调用对象
class Foo:
def __call__(self, *args, **kwargs):
print(self) #<__main__.Foo object at 0x0000000001DBB128>
print(args) #(1, 2, 3)
print(kwargs) #{'a': 1, 'b': 2, 'c': 3}
obj=Foo() #obj之所以可以调用是因Foo里边有个__call__方法
obj(1,2,3,a=1,b=2,c=3) #obj.__call__(obj,1,2,3,a=1,b=2,c=3)
# #元类内部也应有有一个__call__方法,会在调用Foo时触发该方法的执行
# #Foo(1,2,x=1) #Foo.__call__(Foo,1,2,x=1)
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名的首字母必须大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs): #obj=Chinese('egon',age=18) #一个类实例化的行为就是__call__里边的内容
# print(self) #self=Chinese
# print(args) #args=('egon',)
# print(kwargs) #kwargs={'age': 18}
#之前学的是调用Chinese所要做的三件事情: ##这其实就是__call__方法内部
#第一件事:先造一个空对象obj
obj=object.__new__(self) #self= Chinese
#第二件事:初始化obj
self.__init__(obj,*args,**kwargs) #把空对象传进来,把参数传进来
#第三件事:返回obj
return obj
class Chinese(object,metaclass=Mymeta):
'''
中文人的类
'''
country='China'
def __init__(self,namem,age):
self.name=namem
self.age=age
def talk(self):
print('%s is talking' %self.name)
obj=Chinese('egon',age=18) #Chinese.__call__(Chinese,'egon',18) 调用这个对象会触发它的类Mymeta,下面那个__call__
print(obj.__dict__) #{'name': 'egon', 'age': 18}
应用
#单例模式 对象内部特征是一样的话就不要产生空间,用一个空间就可以了,节省空间
#实现方式一:
class MySQL:
__instance=None #__instance=obj1
def __init__(self):
self.host='127.0.0.1'
self.port=3306
@classmethod
def singleton(cls):
if not cls.__instance:
obj=cls()
cls.__instance=obj
return cls.__instance
def conn(self):
pass
def execute(self):
pass
# obj1=MySQL()
# obj2=MySQL()
# obj3=MySQL()
# print(obj1)
# print(obj2)
# print(obj3)
obj1=MySQL.singleton()
obj2=MySQL.singleton()
obj3=MySQL.singleton()
print(obj1 is obj3)
#实现方式二:元类的方式
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名的首字母必须大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,且注释不能为空')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
self.__instance=None #设置个属性
def __call__(self, *args, **kwargs): #obj=Chinese('egon',age=18)
if not self.__instance: #没有__instance就给它造一个
obj=object.__new__(self) #造一个空对象
self.__init__(obj) #self代表Mysql
self.__instance=obj
return self.__instance #有就返回
class Mysql(object,metaclass=Mymeta):
'''
Mysql xxx
'''
def __init__(self):
self.host='127.0.0.1'
self.port=3306
def conn(self):
pass
def execute(self):
pass
obj1=Mysql() #调用这个对象触发__call__下面的方法
obj2=Mysql()
obj3=Mysql()
print(obj1 is obj2 is obj3)
5. __init__和__new__方法
class TestCls():
"""docstring for TestCls"""
def __init__(self, name):
print('init')
print(self)
print(type(self))
self.name = name
def __new__(cls, name):
print('new')
print(cls)
print(type(cls))
return super().__new__(cls)
c = TestCls("CooMark")
# new...
# <class '__main__.TestCls'>
# <class 'type'>
# init...
# <__main__.TestCls object at 0x02201130>
# <class '__main__.TestCls'>
异同点
- 参数
- __new__的第一个占位参数是class对象
- __init__的第一个占位参数是class的实例对象
- 其他的参数应一致
- 作用
- __new__ 用来创建实例,在返回的实例上执行__init__,如果不返回实例那么__init__将不会执行
- __init__ 用来初始化实例,设置属性什么的
__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码
class PositiveInteger(int):
def __init__(self, value):
super().__init__(self, abs(value))
i = PositiveInteger(-3)
print(i)
# # TypeError: object.__init__() takes no parameters
class PositiveInteger(int):
def __new__(cls, value):
return super(PositiveInteger, cls).__new__(cls, abs(value))
i = PositiveInteger(-3)
print(i)
# 3
- 用__new__来实现单例
class Singleton(object):
def __new__(cls):
# 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = 'value1'
print( obj1.attr1, obj2.attr1)
print( obj1 is obj2)
参考:http://www.jb51.net/article/48044.htm
__new__: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
__init__ : 对象的初始化, 是一个实例方法,第一个参数是self。
__call__ : 对象可call,注意不是类,是对象。
先有创建,才有初始化。即先__new__,而后__init__。
__call__方法 对象可call,注意不是类,是对象。
当实现了这个方法时,这个类的实例(对象)可以当作函数一样调用。
比如类A实现了__call__(self, x), 那么
a = A()
a(x) #把a当函数使
面向对象的软件开发
面向对象的软件工程包括下面几个部:
1.面向对象分析(object oriented analysis ,OOA)
软件工程中的系统分析阶段,要求分析员和用户结合在一起,对用户的需求做出精确的分析和明确的表述,从大的方面解析软件系统应该做什么,而不是怎么去做。面向对象的分析要按照面向对象的概念和方法,在对任务的分析中,从客观存在的事物和事物之间的关系,归纳出有关的对象(对象的‘特征’和‘技能’)以及对象之间的联系,并将具有相同属性和行为的对象用一个类class来标识。
建立一个能反映这是工作情况的需求模型,此时的模型是粗略的。
2 面向对象设计(object oriented design,OOD)
根据面向对象分析阶段形成的需求模型,对每一部分分别进行具体的设计。
首先是类的设计,类的设计可能包含多个层次(利用继承与派生机制)。然后以这些类为基础提出程序设计的思路和方法,包括对算法的设计。
在设计阶段并不牵涉任何一门具体的计算机语言,而是用一种更通用的描述工具(如伪代码或流程图)来描述
3 面向对象编程(object oriented programming,OOP)
根据面向对象设计的结果,选择一种计算机语言把它写成程序,可以是python
4 面向对象测试(object oriented test,OOT)
在写好程序后交给用户使用前,必须对程序进行严格的测试,测试的目的是发现程序中的错误并修正它。
面向对的测试是用面向对象的方法进行测试,以类作为测试的基本单元。
5 面向对象维护(object oriendted soft maintenance,OOSM)
正如对任何产品都需要进行售后服务和维护一样,软件在使用时也会出现一些问题,或者软件商想改进软件的性能,这就需要修改程序。
由于使用了面向对象的方法开发程序,使用程序的维护比较容易。
因为对象的封装性,修改一个对象对其他的对象影响很小,利用面向对象的方法维护程序,大大提高了软件维护的效率,可扩展性高。
在面向对象方法中,最早发展的肯定是面向对象编程(OOP),那时OOA和OOD都还没有发展起来,因此程序设计者为了写出面向对象的程序,还必须深入到分析和设计领域,尤其是设计领域,那时的OOP实际上
包含了现在的OOD和OOP两个阶段,这对程序设计者要求比较高,许多人感到很难掌握。
现在设计一个大的软件,是严格按照面向对象软件工程的5个阶段进行的,这个5个阶段的工作不是由一个人从头到尾完成的,而是由不同的人分别完成,这样OOP阶段的任务就比较简单了。程序编写者只需要根
据OOd提出的思路,用面向对象语言编写出程序既可。