面向对象分析与设计
概述
-
面向过程
-
分析出解决问题的步骤,然后逐步实现。-----“自己干活”
- 解决问题的步骤
-
例如:婚礼筹办
-
发请柬(选照片、措词、制作)
-
宴席(场地、找厨师、准备桌椅餐具、计划菜品、购买食材)
-
婚礼仪式(定婚礼仪式流程、请主持人)
-
-
公式:程序 = 算法 + 数据结构
-
优点:所有环节、细节自己掌控。
-
缺点:考虑所有细节,工作量大。
-
-
面向对象
-
找出解决问题的人,然后分配职责,建立之间的交互。-----”雇人干活“
-
例如:婚礼筹办
-
发请柬:找摄影公司(拍照片、制作请柬)
-
宴席:找酒店(告诉对方标准、数量、挑选菜品)
-
婚礼仪式:找婚庆公司(对方提供司仪、制定流程、提供设备、帮助执行)
-
-
公式:程序 = 对象 + 交互
-
优点
-
思想层面:
-
可模拟现实情景,更接近于人类思维。
-
有利于梳理归纳、分析解决问题。
-
-
技术层面:
-
高复用:对重复的代码进行封装,提高开发效率。
-
高扩展:增加新的功能,不修改以前的代码。
-
高维护:代码可读性好,逻辑清晰,结构规整。
-
-
-
封装
定义:
-
数据角度讲,将一些基本数据类型复合成一个自定义类型。
- 将多个描述同一种事物的数据复合一个新的数据类型
-
行为角度讲,向类外提供必要的功能,隐藏实现的细节。
- 隐藏细节后,能更加专注一件事情
-
设计角度:考虑封装方式,考虑封装程度,考虑类的内部,考虑类与类关系
-
分而治之()
-
将一个大的需求分解为许多类,每个类处理一个独立的功能。
-
拆分好处:便于分工,便于复用,可扩展性强。
-
活字印刷:错字容易修改、文字能复用
-
雕版印刷:错字难修改、文字不能复用
-
-
封装变化(一个变化点一个类)
- 变化的地方独立封装,避免影响其他类。
-
高内聚
- 类中各个方法都在完成一项任务(单一职责的类)。
-
低耦合
- 类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。
-
-
作用
-
松散耦合,降低了程序各部分之间的依赖性。
-
数据和操作相关联,方法操作的是自己的数据。
-
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
-
-
[例如:硬件高度集成化,又要可插拔]
- 最高的内聚莫过于类中仅包含1个方法,将会导致高内聚高耦合。
- 最低的耦合莫过于类中包含所有方法,将会导致低耦合低内聚。
继承
-
作用 :隔离客户端代码与功能的实现方式(隔离用和做)。 隔离变化,当子类存在变化时,可抽象出父类用来约束子类,为之后的扩展子类固定模板。
-
适用性:多个类在概念上是一致的,且需要进行统一的处理。
-
设计角度:先有子类 再有父类 抽象化过程
-
编码角度:先有父类 再有子类 具体化过程
多态
-
定义:父类的同一种动作或者行为,在不同的子类上有不同的实现。
-
作用:
-
继承将相关概念的共性进行抽象,多态在共性的基础上,体现类型的个性化(一个行为有不同的实现)。
-
增强程序扩展性,体现开闭原则。
-
-
重写:子类实现了父类中相同的方法(方法名、参数),在调用该方法时,实际调用的是子类的方法。
设计原则
-
开闭原则(目标、总的指导思想)Open Closed Principle
- 对扩展(新功能)开放,对修改(原代码)关闭。
-
类的单一职责(一个类的定义) Single Responsibility Principle
- 一个类有且只有一个改变它的原因。
-
依赖倒置(依赖抽象) Dependency Inversion Principle
-
客户端代码(调用的类)尽量依赖(使用)抽象的组件(父类)。 而不是依赖变化的子类。
-
抽象的是稳定的。实现是多变的。
""" 手雷爆炸了,可能伤害敌人、玩家、还可能伤害未知的事物(鸭子,树木) 要求:如果在增加事物,不影响手雷的代码 体会原则:开闭原则 依赖倒置 """ # ---------------使用者--------------- class Grenade: def explode(self, target): # 如果对象没有继承InjuredObject父类,则报错 if isinstance(target, InjuredObject): print("手雷爆炸了") target.injured() else: raise NotImplemented # 父类起到隔离变化的作用 class InjuredObject: def __init__(self, name): self.name = name #如果子类没有该方法就会报错 def injured(self): raise IndentationError # ------------定义者------------- class Emeny(InjuredObject): def injured(self): print("%s受伤了" % self.name) class Player(InjuredObject): def injured1(self): print("%s受伤了" % self.name)
-
-
组合复用原则(复用的最佳实践) Composite Reuse Principle
-
如果仅仅为了代码复用优先选择组合复用,而非继承复用。
-
组合的耦合性相对继承低。
-
-
里氏替换(继承后的重写,指导继承的设计) Liskov Substitution Principle
-
父类出现的地方可以被子类替换,在替换后依然保持原功能(重写)。
-
子类要拥有父类的所有功能。
-
子类在重写父类方法时,尽量选择扩展重写(使用super()先调用父类方法),防止改变了功能。
-
-
迪米特法则(类与类交互的原则:低耦合) Law of Demeter
-
不要和陌生人说话。
-
类与类交互时,在满足功能要求的基础上,传递的数据量越少越好。因为这样可能降低耦合度。
-
类与类的关系
-
作用域:起作用的范围
-
泛化:子类与父类的关系,概念的复用,耦合度最高;
-
特化(从父到子)B类泛化A类,意味B类是A类的一种;
-
做法:B类继承A类
-
-
关联(聚合/组合):部分与整体的关系,功能的复用,变化影响一个类;
-
A与B关联,意味着B是A的一部分;
-
做法:在A类中包含B类型成员。
-
-
依赖:合作关系,一种相对松散的协作,变化影响一个方法;
-
A类依赖B类,意味A类的某些功能靠B类实现;
-
做法:B类对象作为A类中方法的参数,并不是A的成员。
-