五.面向对象编程
Posted huiguizhe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五.面向对象编程相关的知识,希望对你有一定的参考价值。
1.面向过程与面向对象
1.1面向过程(Procedure Oriented 简称PO :像C语言):
面向过程注重过程的。当解决一个问题的时候,面向过程会把事情拆分成: 一个个函数和数据(用于方法的参数) 。然后按照一定的顺序,执行完这些方法(每个方法看作一个个过程),等方法执行完了,事情就搞定了。
1.2面向对象(Object Oriented简称OO :像C++,JAVA等语言):
面向对象注重对象的。当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。
1.3两者的区别
面向对象是将事物高度抽象化,而面向过程是一种自顶向下的编程
1.4两者各自的优缺点
面向过程
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、
面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低
2.面向对象编程
1.1 对象(Object) :
一个对象是一个类实例化后的实例,可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性
1.2 类(class):
一个共享相同结构和行为的对象的集合。类(Class)定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的(它的行为)。举例来说,“狗”这个类会包含狗的一切基础特征,
例如它的孕育、毛皮颜色和吠叫的能力。类可以为程序提供模版和结构。一个类的方法和属性被称为“成员”
1.3 封装(encapsulation):
目的是隐藏实现细节,使代码模块化
1.6 五大基本原则:SPR, OCP, LSP, DIP, ISP
1.6.1 单一职责原则SRP(Single Responsibility Principle)
是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
1.6.2 开放封闭原则OCP(Open-Close Principle)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。
1.6.3 里式替换原则LSP(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。
1.6.4 依赖倒置原则DIP(the Dependency Inversion Principle DIP)
具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能 造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。
1.6.5 接口分离原则ISP(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来
1.6.6 耦合
简单地说,软件工程中对象之间的耦合度就是对象之间的依赖性。指导使用和维护对象的主要问题是对象之间的多重依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。
有软硬件之间的耦合,还有软件各模块之间的耦合。
耦合性是程序结构中各个模块之间相互关联的度量。它取决于各个模块之间的接口的复杂程度、调用模块的方式以及哪些信息通过接口。
耦合可以分为以下几种,它们之间的耦合度由高到低排列如下:
- 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
- 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
- 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
- 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
- 标记耦合 。若一个模块A通过接口向两个模块B和C传递一个公共参数,那么称模块B和C之间存在一个标记耦合。
- 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
- 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。
总结
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
1.6.7 内聚与耦合
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。
耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
3 类的实例
3.1类的属性和方法,构造函数
class Rloe(): a = 123#类变量 def __init__(self,name,role,weapon,life_value=100, money= 15000): #构造函数,在实例化时初始化类 self.name = name#实例变量(静态属性),赋给了实例,作用域是实例本事(r1) self.role = role self.weapon = weapon self.life_value = life_value self.money = money def shot(self):#类的方法,(动态属性) print("shooting..") def got_shot(self): print("ah....,I got shot....") def buy_gun(self,gun_name): print("%s just bought %s" %(self.name,gun_name)) r1 = Rloe("alex","police","ak47")#实例化一个对象,也叫Role的实例 # r1.buy_gun("ak47") # r1.bullet = True#添加一个属性 # print(r1.bullet) # del r1.weapon#删除一个属性 # print(r1.weapon) Rloe.a = "adc" print(r1.a)
3.2 类的私有属性和私有方法,析构函数
class Rloe(): a = 123#类变量,共用属性,节省开销 def __init__(self,name,role,weapon,life_value=100, money= 15000): #构造函数,在实例化时初始化类 self.name = name#实例变量(静态属性),赋给了实例,作用域是实例本事(r1) self.role = role self.weapon = weapon self.__life_value = life_value#变为了私有属性 self.money = money # def __del__(self):#析构函数:在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作,如关闭一些数据库链接,关闭文件 # print("%s 彻底死了。。。"%self.name) def life(self):#内部调用 print("%s 的生命是%s"%(self.name,self.__life_value)) def shot(self):#类的方法,(动态属性) print("shooting..") def __got_shot(self):#私有方法 print("ah....,I got shot....") def buy_gun(self,gun_name): print("%s just bought %s" %(self.name,gun_name)) r1 = Rloe("alex","police","ak47") # r1.shot() # print(r1.__life_value)#变为私有属性后无法查看和修改,但能通过调用内部方法来查看 r1.life() r1.__got_shot()#私有方法也无法调用
3.3 继承
单继承
继承和重构父类方法
class Pople(): def __init__(self,name,age): self.name = name self.age = name def eat(self): print("%s is eating "%self.name) def sellp(self): print("%s is sleeping......"%self.name) def talk(self): print("%s is taking..."%self.name) class Man(Pople): # def sellp(self):#将覆盖父类中的方法 # print("%s is go to sleeping......"%self.name) def sellp(self): Pople.sellp(self)#重构父类方法,加了新功能 print("%s is go to sleeping......"%self.name) class Woman(Pople): def get_birth(self): print("%s is born a baby...."%self.name) m1 = Man("alex",22) m1.eat() m1.sellp() w1 = Woman("ming",23) w1.get_birth()
继承和重构构造函数,添加属性
class Pople(): def __init__(self,name,age): self.name = name self.age = name def eat(self): print("%s is eating "%self.name) def sellp(self): print("%s is sleeping......"%self.name) def talk(self): print("%s is taking..."%self.name) class Man(Pople): def __init__(self,name,age,money):#重构构造函数,添加属性 # Pople.__init__(self,name,age)#调用继承父类属性 super(Man,self).__init__(name,age)#另一种调用方法 self.money = money#添加新属性 print("%s 一出生就有%s¥"%(self.name,self.money)) # def sellp(self):#将覆盖父类中的方法 # print("%s is go to sleeping......"%self.name) def sellp(self): Pople.sellp(self)#重构父类方法,加了新功能 print("%s is go to sleeping......"%self.name) class Woman(Pople): def get_birth(self): print("%s is born a baby...."%self.name) m1 = Man("alex",22,10) m1.eat() m1.sellp() w1 = Woman("ming",23) w1.get_birth()
多继承
class Pople(object):#新式类与经典类的区别在于类的继承上 # class Pople:#经典类 def __init__(self,name,age): self.name = name self.age = name def eat(self): print("%s is eating "%self.name) def sellp(self): print("%s is sleeping......"%self.name) def talk(self): print("%s is taking..."%self.name) class Relation(object): def make_friend(self,obj): print("%s is making friends with %s"%(self.name,obj.name)) class Man(Pople,Relation): def __init__(self,name,age,money):#重构构造函数,添加属性 # Pople.__init__(self,name,age)#调用继承父类属性 super(Man,self).__init__(name,age)#另一种调用方法 self.money = money#添加新属性 print("%s 一出生就有%s¥"%(self.name,self.money)) # def sellp(self):#将覆盖父类中的方法 # print("%s is go to sleeping......"%self.name) def sellp(self): Pople.sellp(self)#重构父类方法,加了新功能 print("%s is go to sleeping......"%self.name) class Woman(Pople,Relation): def get_birth(self): print("%s is born a baby...."%self.name) m1 = Man("alex",22,10) # m1.eat() # m1.sellp() w1 = Woman("ming",23) # w1.get_birth() m1.make_friend(w1)
p3继承都是按广度优先
class A:#p3都是广度优先,p2经典类是按深度优先来继承,新式类按广度优先 def __init__(self): print("A") class B(A): pass # def __init__(self): # print("B") class C(A): pass # def __init__(self): # print("C") class D(B,C): pass # def __init__(self): # print("D") D()
class School(object): def __init__(self,name,addr): self.name = name self.addr = addr self.students = [] self.teachers = [] self.staffs = [] def enroll(self,stu_obj):#办理 print("为学员%s 办理注册手续"%stu_obj.name) self.students.append(stu_obj) def hire(self,stu_obj): self.staffs.append(stu_obj) print("雇用新员工%s"%stu_obj.name) class SchoolMember(object):#备用 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def tell(self): pass class Teacher(SchoolMember): def __init__(self,name,age,sex,salary,course): super(Teacher,self).__init__(name,age,sex) self.salary = salary self.course = course def tell(self): print(‘‘‘--info of Teacher:%s-- Name:%s Age:%s Sex:%s Salary:%s Course:%s ‘‘‘%(self.name,self.name,self.age,self.sex,self.salary,self.course)) def teach(self): print("%s is teaching cours [%s]"%(self.name,self.sex)) class Student(SchoolMember): def __init__(self,name,age,sex,stu_id,grade): super(Student,self).__init__(name,age,sex) self.stu_id = stu_id self.grade = grade def tell(self): print(‘‘‘--info of Student:%s-- Name:%s Age:%s Sex:%s Stu_id:%s Grade:%s ‘‘‘%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade)) def pay_tution(self,amout): print("%s has paid tution for $%s"%(self.name,amout)) school = School("老男孩IT","沙河") t1 = Teacher("Oldbay",56,"man",10000,"java") s1 = Student("01student",23,"man","110","1") s1.tell() t1.tell() school.enroll(s1) school.hire(t1)
3.4 多肽(一个接口多种实现)
‘‘‘ class Animal(object): def __init__(self,name): self.name = name def talk(self): pass class Cat(Animal): def talk(self): print( "Meow!") class Dog(Animal): def talk(self): print("Woof! Woof!") def animal(obj): obj.talk() d1 = Dog("hua")#要调用方法,要用两个接口,d1和c1 # d1.talk() c1 = Cat("hua") # c1.talk() animal(c1)#用一个接口就实现了调用两个方法 animal(d1) ‘‘‘ class Animal(object): def __init__(self,name): self.name = name def talk(self): pass @staticmethod#装饰器 def animal(obj): obj.talk() class Cat(Animal): def talk(self): print( "Meow!") class Dog(Animal): def talk(self): print("Woof! Woof!") d1 = Dog("hua")#要调用方法,要用两个接口,d1和c1 # d1.talk() c1 = Cat("hua") # c1.talk() Animal.animal(c1)#用一个接口就实现了调用两个方法 Animal.animal(d1)
3.4 静态方法
#静态方法 ,在静态方法中是访问不了类的方法 class Dog(object): def __init__(self,name): self.name = name @staticmethod#用它,相当于把eat方法截取出来,跟Dog类没关系了,就没有self了 def eat(self,food): print("%s is eating %s"%(self.name,food)) d = Dog("ming") d.eat("包子")
类方法
#类方法 class Dog(object): name = "liu" def __init__(self,name): self.name = name @classmethod#类方法,只能访问类变量,不能访问实例变量 def eat(self): print("%s is eating %s"%(self.name,"dd")) d = Dog("ming") d.eat()
属性方法
class Dog(object): def __init__(self,name): self.name = name self.__food = None @property#属性方法,把一个方法变为一个静态属性 def eat(self): print("%s is eating %s"%(self.name,self.__food)) @eat.setter def eat(self,food): print("set to food:",food) self.__food =food # @eat.deleter#内部删除 # def eat(self, food): # del self.__food = food # print("删完了") d = Dog("ming") d.eat d.eat = "baozi" # del eat#无法正规删除
#静态方法应用 #1.连接航空公司API查询 #2.对查询结果进行解析 #3.返回结果给你的用户 class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status "%self.flight_name)#相当于调api,并返回结果 return 1 @property def flight_status(self): status = self.checking_status() if status == 0: print("flight got canceled...") elif status == 1: print("flight is arrived....") elif status == 2: print("flight has departured already...") else: print("connot confirm the flight status....,please check") f = Flight("CA980") f.flight_status
3.5 其他方法
class Dog(object): """这个类是描述狗这个对象的"""#描述字符 def __init__(self,name): self.name = name def eat(self,food): print("%s is eating %s"%(self.name,food)) d = Dog("ming") d.eat("包子") 1 # print(Dog.__doc__)#打印描述字符 print(d.__module__) print(d.__class__) 2 # __module__表示当前操作在哪个模块, 3 # __class__ 表示当前操作的对象的类是什么 class Dog(object): """这个类是描述狗这个对象的"""#描述字符 def __init__(self,name): self.name = name def eat(self,food): print("%s is eating %s"%(self.name,food)) def __call__(self, *args, **kwargs):#4 __call__方法 print("running call",args,kwargs) d = Dog("ming") d(1,2,3,name="alex") 5.#__dict__查看类和对象中的所有成员 print(Dog.__dict__)#查看类中的所有属性 print(d.__dict__)#查看实例属性 6.class Dog(object): """这个类是描述狗这个对象的"""#描述字符 def __init__(self,name): self.name = name def eat(self,food): print("%s is eating %s"%(self.name,food)) def __str__(self):# return "<obj:%s>"%self.name d = Dog("ming") print(d) 7.创建类 def func(self): print("hello %s"%self.name) def __init__(self, name): self.name = name # Foo = type("Foo",(object,),{"key":func})#创建一个类Foo Foo = type("Foo", (object,), {"key": func, "__init__":__init__}) # 合在一起创建一个类 f=Foo("alex") f.key() print(type(Foo)) 8.#原类的创建, class MyType(type): def __init__(self,what,bases=None,dict=None): print("--MyType init--") super(MyType,self).__init__(what,bases,dict) def __call__(self, *args, **kwargs): print("--MyType call--") obj = self.__new__(self,*args,**kwargs)#调用了new self.__init__(obj,*args,**kwargs)#调用了init class Foo(object): __metaclass__ = MyType def __init__(self,name): self.name = name print("Foo-- init__") def __new__(cls, *args, **kwargs):#new实例化了对象(代替了init),创建了实例,cls相当于Foo print("Foo--new--") return object.__new__(cls)#继承父类的new方法 Foo("alex")
3.6 反射
通过字符串映射或修改程序运行时的状态、属性、方法
# gatattr # setattr # hasattr # delattr def bulk(self): print("%s is take"%self.name) class Dog(object): def __init__(self,name): self.name = name def eat(self,food): print("%s is eating...."%self.name,food) d = Dog("hua") choice = input(">>:").strip() # d.choice#无法调用 # print(hasattr(d,choice))#判断d中是否有choice这个方法,根据映射,有则返回True # print(getattr(d,choice))#调用内存地址 # print(getattr(d,choice)())#显示内容 if hasattr(d,choice): func = getattr(d,choice) func("包子") # if hasattr(d,choice): # delattr(d,choice) else: # setattr(d,choice,bulk)#d.choice = bulk # d.talk(d)#调用要用talk setattr(d,choice,None)#加入一个静态属性 print(getattr(d,choice))#可以直接返回 # print(d.name)
# mod = __import__("lib.aa")#mod = lib#动态加载lib下的模块aa # print(mod.aa.C().name) import importlib aa = importlib.import_module("lib.aa")#直接导入aa print(aa.C().name)
3.7 自定义异常
class AlexException(Exception): def __init__(self,msg): self.message = msg def __str__(self): return self.message #返回值 try: raise AlexException("我的异常") except AlexException as e: print(e)
#断言 a = "aa" assert type(a) is str#相当于判断 print("你输入了一个字符串")
以上是关于五.面向对象编程的主要内容,如果未能解决你的问题,请参考以下文章