面向对象

【一】什么是面向过程

【1】面向过程介绍

  • 面向过程,核心在于 “过程” 二字
  • 过程的终极奥义就是将程序 “流程化”
  • 过程是 “流水线” ,用来分步骤解决问题的
  • 过程指的是解决问题的步骤,即先干什么再干什么......
  • 面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。

【2】面向过程的优点

  • 复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)

【3】面向过程的缺点

  • 一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。

【二】什么是面向对象

【1】面向对象介绍

  • 面向对象,核心在于“对象”二字
  • 对象的终极奥义就是将程序 “整合”
  • 对象就是 “容器” ,用来盛放数据与功能

(1)面向对象理解文字版

  • 面向对象就相当于上帝,在上帝的视角,人是对象,动物是对象,石头是对象,水是对象,山是对象,存在的可以扩充,不存在的可以创造。

(2)面向对象设计理解文字版

  • 面向对象的设计就好比我们要设计一个小校园模拟器,我们需要在校园中创造各种生活场景,包括上课、做饭、打球等等。
  • 这些场景对应的角色就是对象,比如老师、学生、运动员、厨师等。
  • 而每一个角色都会对应其具有的责任和功能
    • 比如一个学生具有姓名、年龄、性别、所在班级等。
    • 学生还有能做的活动,读书、写作、跑步、打篮球等。
    • 比如一个老师可以教书、批改作业等。
    • 比如运行员可以参加训练和比赛等。
  • 当我们的角色和功能构建好以后,我们又需要创建几个学生、一些老师和运行员,让他们进行各项活动。
    • 比如一个学生可以上课、写作业、运动;
    • 比如一个老师可以教课、批改作业;
    • 比如一个运动员可以训练、参加比赛

【2】面向对象的优缺点

(1)面向对象的优点

  • 解决了程序的扩展性。
  • 对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。

(2)面向对象的缺点

  • 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。
    • 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
  • 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。
    • 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。

【3】什么是程序

  • 程序 = 数据 + 功能
  • 编写程序的本质就是定义出一系列的数据,然后定义出一系列的功能来对数据进行操作。

【4】人狗大战小游戏

def dog(dog_name, dog_type, attack, health):
def dog_attack_person(dog: dict, person: dict):
person['health'] -= dog['attack']
print(f'{dog["dog_name"]} 咬了{person["person_name"]} 掉了{dog["attack"]} 血')
dog_dict = {
'dog_name': dog_name,
'dog_type': dog_type,
'attack': attack,
'health': health,
'dog_attack_person': dog_attack_person
}
return dog_dict
def person(person_name, person_sex, attack, health):
def person_attack_dog(dog: dict, person: dict):
dog['health'] -= person['attack']
print(f'{person["person_name"]} 打了{dog["dog_name"]} 掉了{person["attack"]} 血')
dog_dict = {
'person_name': person_name,
'person_sex': person_sex,
'attack': attack,
'health': health,
'person_attack_dog': person_attack_dog
}
return dog_dict
dog1 = dog(dog_name='旺财', dog_type='哈士奇', attack=10, health=100)
dog2 = dog(dog_name='小狗', dog_type='田园犬', attack=20, health=100)
person = person(person_name='heart', person_sex='男', attack=30, health=100)
dog1['dog_attack_person'](dog1, person) # 旺财 咬了heart 掉了10 血
person['person_attack_dog'](dog1, person) # heart 打了旺财 掉了30 血
  • 总结:
  • 上述函数都是将数据和功能进行绑定,人具有自己的属性,可以有自己相应的功能。
  • 当我们初始化我们的函数得到一个狗的对象的时候,只有调用这只狗产生狗咬人的功能时,影响到的只有这只狗。

【5】小结

  • 将数据和功能绑定在一起就是面向对象的思想

  • 在了解了对象的基本概念之后,理解面向对象的编程方式就相对简单很多了

  • 面向对象编程就是要造出一个个的对象,把原本分散开的相关数据与功能整合到一个个的对象里

  • 这么做既方便使用,也可以提高程序的解耦合程度,进而提升了程序的可扩展性(需要强调的是,软件质量属性包含很多方面,面向对象解决的仅仅只是扩展性问题)

【三】面向对象编程

【1】引入

  • 按照上述的理论我们来定义一个类
  • 我们构建一个学校:先有对象,后有类

(1)对象

  • 对象(Object): 对象是程序中的基本单元,它包含数据和操作数据的方法。对象可以是现实世界中的实体,如人、车,也可以是更抽象的概念,如文件、日期。

  • 他们都有共同的属性:学校,能力

对象1:
heart
特征:
学校=heartschool
姓名=heart
性别=男
年龄=18
能力:
读书
写作
跑步
对象2:
god
特征:
学校=heartschool
姓名=god
性别=男
年龄=20
能力:
读书
写作
跑步
对象3:
ming
特征:
学校=heartschool
姓名=ming
性别=女
年龄=20
能力:
读书
写作
跑步

(2)类

  • 类(Class): 类是对象的模板或蓝图,定义了对象的属性和方法。对象是根据类创建的实例。类可以看作是一种数据类型,描述了对象的共同特征和行为。
构建的学校的类:
相似的特征:
学校=heartschool
相似的技能:
读书
写作
跑步
class 类名():
# 定义参数
# 定义函数

(3)调用类

  • 在面向对象编程中,调用类通常指的是创建类的实例(对象)并使用这个实例调用类中的方法或访问类的属性。
class HeartStudent():
school = 'heartschool'
def read(self):
print(f'可以读书')
def write(self):
print(f'可以写作')
def run(self):
print(f'可以跑步')
stu1 = HeartStudent() # 创建类的实例
print(dir(stu1)) # 查看其有的方法
stu1.read() # 调用类的方法 输出:可以读书
print(stu1.school) # 访问类的属性 输出:heartschool
  • 步骤:

    • 创建类的实例
    stu1 = HeartStudent()
    • 调用类的方法
    stu1.read()
    • 访问类的属性
    print(stu1.school)

(4)魔法方法 init

(1)__init__初始化类

  • __init__:这是一个特殊的方法,在创建类的实例时自动调用,用于对象的初始化。
  • self:表示类的实例对象,即将要被初始化的对象。
  • name, age, gender:这些是构造方法的参数,用于传递对象的属性值。
  • self.name, self.age, self.gender:这些是对象的属性,通过构造方法的参数初始化。这些属性将存储有关对象的信息,如姓名、年龄和性别。
  • 当创建一个类的实例时,构造方法会自动调用,并将提供的参数值用于初始化对象的属性。
class ATM:
user_data_dict = {}
def __init__(self):
self.username = ''
self.password = ''
# 注册
def register(self):
username = input('请输入用户名:>>>').strip()
password = input('请输入密码:>>>').strip()
ATM.user_data_dict['username'] = username
ATM.user_data_dict['password'] = password
print('注册成功!')
# 登录
def login(self):
username_input = input('请输入用户名:>>>').strip()
password_input = input('请输入密码:>>>').strip()
if username_input == ATM.user_data_dict.get('username') and password_input == ATM.user_data_dict.get('password'):
print('登录成功!')
self.username = username_input # 将实例的username属性设置为用户输入的值
self.password = password_input # 将实例的password属性设置为用户输入的值
else:
print('登录失败!')
# 示例用法:
atm = ATM()
atm.register()
atm.login()
# 输出登录成功后的用户名和密码
print('当前用户名:', atm.username)
print('当前密码:', atm.password)

【2】类属性和对象属性

(1)类属性和对象属性

  • 在类中定义的名字,都是类的属性,类有两种属性:
    • 数据属性和函数属性
    • 可以通过__dict__访问属性的值,比如Student.__dict__['school'],但Python提供了专门的属性访问语法
# 类属性: 分为两种 一种是数据属性 一种是函数属性
class Student():
# 这个 school 其实就是数据属性,对象可以任意调用
school = 'heartschool'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
print(f'正在读书')
stu = Student(name='heart', age=18, gender='男')

(1)访问数据属性的两种方法:

  • 一种是通过__dict__的字典取键
stu = Student(name='heart', age=18, gender='男')
print(Student.__dict__)
# {'__module__': '__main__', 'school': 'heartschool', '__init__': <function Student.__init__ at 0x000002A71AB6B0A0>, 'read': <function Student.read at 0x000002A71AE18EE0>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
print(Student.__dict__['school']) # heartschool
  • 另一种直接通过 类名.属性 获取到属性的值
  • 实例化对象也可以通过 对象名.属性 获取到属性的值,因为是从实例化它的类里面找出来的
stu = Student(name='heart', age=18, gender='男')
print(Student.school) # heartschool
print(stu.school) # heartschool

(2)对象的属性查找顺序:

  • 首先从自己本身开始找 从 stu.__dict__开始找
  • 找不到再去实例化他的类中找 Student.__dict__
  • 别的方法没有初始化过这个属性,并且这个类没有继承其他的类,找不到就报错了
  • 总结: obj(开始) ---> class(类) ---> gender_class(父类) ---> 找不到直接报错

(2)访问函数属性的两种方法

# 类属性: 分为两种 一种是数据属性 一种是函数属性
class Student():
# 这个 school 其实就是数据属性,对象可以任意调用
school = 'heartschool'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
print(f'正在读书')
stu = Student(name='heart', age=18, gender='男')
# 类调用对象函数属性 因为有一个位置参数self 类调用需要传入self(实例化出来的对象)
Student.__dict__['read'](stu) # 正在读书
# 对象调用函数属性 这里的位置参数会自动将调用该方法的对象传入,所以不用传self参数
stu.read() # 正在读书

【四】类的特殊属性

  • 类名.__name__ :类的名字(字符串)
  • 类名.__doc__:类里的注释(字符串)
  • 类名.__base__:类的第一个父类
  • 类名.__bases__:类的所有父类(元组)
  • 类名.__dict__:类的字典属性(所有属性)
  • 类名.__module__:类定义所在的模块
  • 类名.__class__:实例对应的类(仅新式类中)
class Animal():
...
class People():
...
class Heart(Animal, People):
'''2024 up up!'''
def __init__(self, name, age):
self.name = name
self.age = age
def run(self):
print(f"{self.name}跑步!")
# 类名.__name__:类的名字(字符串)
print(Heart.__name__) # Heart
# 类名.__doc__:类里的注释(字符串)
print(Heart.__doc__) # 2024 up up!
# 类名.__base__:类的第一个父类
print(Heart.__base__) # class '__main__.People'>
# 类名.__bases__:类的所有父类(元组)
print(Heart.__bases__) # (<class '__main__.Animal'>, <class '__main__.People'>)
# 类名.__dict__:类的字典属性(所有属性)
print(Heart.__dict__) # {'__module__': '__main__', '__doc__': '2024 up up!', '__init__': <function Heart.__init__ at 0x000001D63734A4D0>, 'run': <function Heart.run at 0x000001D63734B0A0>, '__dict__': <attribute '__dict__' of 'Heart' objects>, '__weakref__': <attribute '__weakref__' of 'Heart' objects>}
# 类名.__module__:类定义所在的模块
print(Heart.__module__) # __main__
# 类名.__class__:实例对应的类(仅新式类中)
print(Heart.__class__) # <class 'type'>
posted @   ssrheart  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示