[Python]面向对象

面向过程和面向对象的对比

面向过程

        面向过程是按照问题的解决方式来编写程序。需要先分析出解决问题的方法,然后按照这个方法一步步的去完成程序,所有细节都需要自己去实现,优点是程序细节自己把握,缺点是工作量巨大。

比如:出门旅游

  1. 买票(去买票:买高铁 or 飞机, 买什么座位,出发时间,下单)
  2. 出发(去车站or机场: 几点出发几点到,打车or地铁)
  3. 游玩景点(玩哪些景点,每个景点多长时间)
  4. 回家(重复步骤1和2)                                       

面向对象

        面向对象,更贴近人的思维模式,处理问题需要找到对应的人,然后解决问题。面向对象能使程序员从软件架构的方向去思考程序的开发,有助于梳理结构分析问题。

面向对象的三大特征如下:

  • 封装
  • 继承
  • 多态

有利于代码的复用提高编码效率,可扩展性很强,增加新功能不需要修改原来的代码,软件逻辑结构清晰,有助于后期维护。

比如:出门旅游

  • 找旅游公司:
    • 买票
    • 接送机
    • 景点安排
    • 回程接送

一站式服务,不需要自己亲自处理。

类和对象:

  • 类:从具体事务中抽象出共性,比如人类(泛指整个人类)是从每个个人中抽象出共有的特征,从而形成人类的群体。
    class StudentInformation:
        def __init__(self, name):
            self.name = name
            
        def read_stu(self):
            pass
    • 类成员:定义在__init__方法之外,需要通过类名来访问,所有对象共享一个类成员,对也可以通过对象来访问
class StudentInformation:
    # 类成员student_number,表示当前student的数量
    student_number = 0

    def __init__(self, name):
        self.name = name
        StudentInformation.student_number +=1

    def read_stu(self):
        pass


stu01 = StudentInformation("abc")
print(stu01.student_number)   # 输出 1
    • 类方法:标识符(@classmethod), 可以访问类成员,不能访问init中的对象成员,因为类方法中没有对象的地址,所以无法访问对象成员。 
    • 作用:操作类变量
    • 通过类名.方法名调用
    @classmethod
    def display_student(cls, **kwargs):
        pass
    
StudentInformation.display_student()

Note:

  •    类名中所有单词首字母大写
  • __init()__为构造函数,在创建对象的时候被调用,可省略
  • self是指向被实例化的对象

对象

  • 对象:实例化的类,归属于某个类别的个体,比如小明(一个具体的人,属于人类)
    • 对象成员:定义在__init__方法以内,通过对象地址来访问
    • 对象方法:无标识符,可以访问操作对象成员和类成员(需要通过类名来访问)
stu01 = StudentInformation("abc")

Note:

  • 首次通过对象赋值为创建,再次赋值为修改.这种新创建的对象成员仅当前对象能用,之后新建的对象没有age这个成员变量
# 创建新对象成员age
stu01.age = 10
# 创建新对象成员age
stu01.age = 20
# age = 20
print(stu01.age)
  • 每个对象存储一份,通过对象地址访问。
  •  静态方法:标识符(@staticmethod), 既不需要操作类变量也不需要操作对象变量,则用静态方法,通过类名调用静态方法(不建议使用对象调用静态方法)
    @staticmethod
    def static_student():
        pass

StudentInformation.static_student()

Note:

  •         使用@ staticmethod修饰的目的是该方法不需要隐式传参数。

        静态方法不能访问实例成员和类成员

        作用:定义常用的工具函数。

 封装

  • 从数据角度来说:
    • 将基本的数据类型复合组成一个自定义类型
    • 优势:将数据和对数据的操作相互关联,代码可读性高
  • 从行为角度来说:
    • 隐藏实现细节,只向外提供必要的功能
    • 调用者不必了解实现细节,只需要知道调用功能即可
    • 私有成员:
      • 作用:无需向类外提供的成员,可通过成员私有化进行屏蔽
      • 语法:使用双下划线开头
      • 类的外部是无法直接访问,需要通过类提供的方法来访问。
      • 使用property来封装类的成员:成员名 = property(成员set类方法,成员get类方法),可以增加相应的逻辑判断
        • 写法1可以单独设置get或者set 属性,而写法2中能单独设置get属性,但是不能单独设置set属性,实际操作多选用写法2.

class Enemy:
    def __init__(self, name, hp, atk):
        self.name = name
        self.hp = hp
        self.atk = atk

#       *******************写法1 start *****************************
    def set_hp(self, hp):
        if 100 < hp < 200:
            self.__hp = hp
        else:
            raise ValueError("hp out of range")

    def get_hp(self):
        return self.__hp
    hp = property(get_hp, set_hp)

    def set_atk(self, atk):
        if 20 < atk < 30:
            self.__atk = atk
        else:
            raise ValueError("atk out of range")

    def get_atk(self):
        return self.__atk

    atk = property(get_atk, set_atk)
#       *******************写法1 end *****************************


#     # *********************写法2 start ********************************
#     # 设置hp读取属性
#     @property
#     def hp(self):
#         return self.__hp
#     # 设置hp 写属性
#     @hp.setter
#     def hp(self,hp):
#         if 100 < hp < 200:
#             self.__hp = hp
#         else:
#             raise  ValueError("hp out of range")
#
#     # 设置atk 读属性
#     @property
#     def atk(self):
#         return self.__atk
#
#     #设置atk 写属性
#     @atk.setter
#     def atk(self, atk):
#         if 20< atk <30:
#             self.__atk = atk
#         else:
#             raise ValueError("atk out of range")
# # ****************写法2 end***********************************

e01 = Enemy("wukong",101,25)
  • 从设计角度来讲:
    • 分而治之:将一个大的需求分解为许多类,每个类处理一个独立的功能。
    • 变则疏之:变化的地方独立封装,避免影响其他类。
    • 高内聚:类中各个方法都在完成一项任务(单一职责的类)。
    • 低耦合:类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。
    • 优势:便于分工,便于复用,可扩展性强

例如软件设计的结构之一 MVC(Model, View, Control)就是使用的这种思想,将界面,数据和逻辑单元分开设计。

多态

设计角度

定义

父类的一种行为在子类中有不同的实现方式。

作用

  1. 在继承的基础上体现类型的个性化(同一种行为的不同实现)
  2. 增强程序的扩展性,体现开闭原则

语法角度

重写

  • 子类中实现了父类中相同的方法(函数名、参数)
  • 在调用子类中该方法时实际使用的是子类中的方法,只有当子类中没有实现该方法时,才调用父类中的该方法
# 父类Thing
class Thing():
    def __init__(self, name):
        self.name = name

    # 子类中必须实现的方法
    def reduce_hp(self):
        raise NotImplementedError


class Granades:

    def damage(self, thing):
        if isinstance(thing, Thing): #判断传入的参数thing是不是要求传入的参数对象Thing
            thing.reduce_hp()
        else:
            raise ValueError("Not Object Things")


# Thing 的子类Tree
class Tree(Thing):
    def __init__(self, name):
        super().__init__(name=name)

    def reduce_hp(self):
        print("手雷炸断了{}".format(self.name))


# Thing 的子类House
class House(Thing):
    def __init__(self, name):
        super().__init__(name=name)

    def reduce_hp(self):
        print("手雷炸塌了{}".format(self.name))


g01 = Granades()
h01 = House("别墅01")
t01 = Tree("大树01")
g01.damage(h01)
g01.damage(t01)

猜你喜欢

转载自blog.csdn.net/x1987200567/article/details/127851921