DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • python面向过程

  • python面向对象

  • 网络并发编程

  • 不基础的py基础

  • 设计模式

    • 单一职责原则
    • OOP和设计原则
      • OOP接口
        • 为什么要接口?
        • 接口的实现
        • 接口的作用
      • SOLID原则
        • 开放封闭原则
        • 里氏替换原则
        • 依赖倒置原则
        • 接口隔离原则
        • 单一职责原则
      • 设计模式
    • 创建型模式
    • 结构型模式
  • python_Need
  • 设计模式
DC
2024-09-18
目录

OOP和设计原则

搭建代码框架 --> 软件设计/软件工程.

面向对象编程有三大特性: 封装、继承、多态 这三者是递进关系的
-1- 封装: 有两方面, 一方面是 将属性和方法放到类里; 另一方面是 __ 双下划线开头,表示私有.
-2- 继承.
-3- 多态: 在python中不用care它, 因为python的语言特性就已经决定了它是多态语言了.

# OOP接口

接口: 若干抽象方法的集合.

# 为什么要接口?

现有两个类,表示两种支付方式,阿里支付和微信支付

class AliPay:
    def pay(self, money):
        pass


class WechatPay:
    def pay(self, money):
        pass
1
2
3
4
5
6
7
8

我们很容易想到通过类实例化得到对象,再调用各自的pay方法完成支付.

a = AliPay()
a.pay(100)
b = WechatPay()
b.pay(100)
1
2
3
4

而在开发时, 我们往往会将 对支付方法pay的调用 封装到一个函数中

# - 高层代码/客户端
def finish_pay(p, money):
    p.pay(money)

# - 客户端使用过程,也可看作是高层代码的一部分
p1 = AliPay()
finish_pay(p1, 100)
p2 = WechatPay()
finish_pay(p2, 100)
1
2
3
4
5
6
7
8
9

进行到这一步,看似没有问题, 实则有个致命的隐患.. 我们得保证 阿里支付和微信支付里的支付方法都是pay!!
如何实现呢? 通过接口来实现.

写了接口后, 在多人协作开发代码时, 一人开发一个支付, 大家都按照接口的定义去写, 即支付方法都是pay..
这样就保证了 [高层] 在调用支付方法时不会出错, 完成了支付方法调用的统一.

# 接口的实现

接口的实现有两种方法, 一种是raise, 一种是抽象类, 我们一般选择后者.

class PayMent:
    def pay(self, money):
        raise NotImplementedError


class AliPay(PayMent):
    pass
1
2
3
4
5
6
7

第一种raise的方式有个问题, p=AliPay() 只要p对象不调用pay方法, 就不会报错..
第二种不实现接口方法的话, p=AliPay() 类实例化时就会报错.. 注: 实现接口时,方法名, 方法参数 都得一样!

from abc import ABCMeta, abstractmethod


class PayMent(metaclass=ABCMeta):  # - 抽象类
    @abstractmethod  # - 约束子类必须重写这个抽象方法,专业点: ★★★ AliPay实现了PayMent的接口!!
    def pay(self, money):
        pass


class AliPay(PayMent):  # - 不能说是继承接口类,应该说是实现接口
    # - 不重写该方法的话,a = AliPay()类实例化时就会报错: 
    #   TypeError: Can't instantiate abstract class AliPay with abstract method pay
    def pay(self, money):
        pass


a = AliPay()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 接口的作用

★ 接口保证了 [高层] 在调用 接口方法时的统一 / 父类强制的规范子类必须要有哪些方法, ★ 还有这么一句话: 接口对高层模块隐藏了类的内部实现.

理解下何为高层模块?
- 针对Django源码而言,我们使用Django的人写的代码就是高层模块.
  Django底层使用了大量设计模式,写了很多接口,让你调用的很舒服
- 针对我们写的支付案例, 对pay接口的调用代码就是高层代码.(简单这样理解就行
1
2
3
4

接口案例完整代码:

from abc import ABCMeta, abstractmethod


class PayMent(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):  # 这是接口. 接口对高层模块隐藏了类的内部实现,接口就方法名、方法参数、返回值类型
        pass


class AliPay(PayMent):
    def pay(self, money):  # 这是实现接口.
        pass


class WechatPay(PayMent):
    def pay(self, money):  # 这是实现接口.
        pass


# - 高层代码/高层模块/客户端
def finish_pay(p, money):
    p.pay(money)

# - 客户端使用过程,也可看作是高层代码的一部分
p1 = AliPay()
finish_pay(p1, 100)  # 在调用的时候,看不到底层类的内部实现/★ 不用你调用pay方法,finish_pay函数里已经写了.
p2 = WechatPay()
finish_pay(p2, 100)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# SOLID原则

面向对象设计的SOLID原则, 5个.

# 开放封闭原则

开闭原则: 对扩展开放,对修改关闭. 即软件实体尽量在不修改原有代码的情况下进行扩展.

# 里氏替换原则

所有引用父类的地方必须能透明的使用其子类对象.

class User:
    def show_name(self):
        pass


class VIPUser(User):
    # 1.应该保证方法名、方法参数、方法的返回值类型与父类是一样的,与父类方法不同的仅是方法里的逻辑
    def show_name(self):
        pass


# - 高层代码/客户端
def show_user(u):  # u可能是User的对象,亦可能是VIPUser的对象
    # 2.进而保证此处写的u.show_name()是不会出错的,eg:不能User的show_name有3个参数,VIPUser的show_name有4个参数.
    return u.show_name()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 依赖倒置原则

-1- 高层模块不应该依赖底层模块..<若依赖,那么底层模块的变动会导致高层模块的代码也改变>
-2- 高层和底层二者应该依赖其抽象..<接口就是抽象,这些接口表明了高层代码需要哪些函数!>
-3- 抽象不应该依赖细节.. <抽象类里接口方法的方法体是pass>
-4- 细节应该依赖抽象.. <实现接口方法, 其方法体里是具体的逻辑>

换言之, 要针对接口编程, 而不是针对实现编程..

from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta):  # 抽象类
    @abstractmethod
    def pay(self, money):  # 接口
        pass


# - Alipay和WechatPay 都是底层模块
class Alipay(Payment):
    def pay(self, money):  # 实现接口 / 细节
        print(f"支付宝支付了{money}元!")


class WechatPay(Payment):
    def pay(self, money):  # 实现接口 / 细节
        print(f"微信支付了{money}元!")


# - 高层模块/客户端 (上面oop接口案例那,用的是函数)
class ShoppingCart:
    def __init__(self, payment: Payment):
        self.payment = payment

    def checkout(self, amount):
        self.payment.pay(amount)

# - 客户端使用过程,也可看作是高层代码的一部分
a = Alipay()
cart1 = ShoppingCart(a)
cart1.checkout(100.0)

w = WechatPay()
cart2 = ShoppingCart(w)
cart2.checkout(200.0)

"""
          ---------------
          |   高层模块   |
          | ShoppingCart |
          ---------------
                |
                ▼
          ---------------
          |    抽象层    |
          |    Payment    |
          ---------------
          ▲             ▲
          |             |
  ----------------   ----------------
  |  底层模块     |   |  底层模块     |
  |  Alipay      |   |  WechatPay  |
  ----------------   ----------------
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 接口隔离原则

使用多个专门的接口,而不使用单一的总接口, 即 客户端/高层代码 不应该依赖那些它不需要的接口.

现有这样一个动物相关的抽象类, 里面有接口 走、游泳和飞.

from abc import ABCMeta, abstractmethod


class Animal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):
        pass

    @abstractmethod
    def swim(self):
        pass

    @abstractmethod
    def fly(self):
        pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

老虎类继承了Animal类, 需实现动物这个抽象类的所有接口, 但老虎不会飞呀, 所以这样的设计不是很合理.

那如何改进呢? 使用接口隔离原则来实现.

from abc import ABCMeta, abstractmethod


class LandAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):
        pass


class WaterAnimal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):
        pass


class SkyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):
        pass


class Tiger(LandAnimal):  # Tiger只会走路,不会游泳和飞
    def walk(self):
        pass


class Frog(LandAnimal, WaterAnimal):  # 继承了两个抽象类,实现了里面的游泳和走路的接口!
    def swim(self):
        pass

    def walk(self):
        pass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 单一职责原则

不要存在多于一个导致类变更的原因, 通俗来说, 即一个类只负责一项职责/一个类只做一件事.

举个极端的例子:
拿到需求后,用面向过程编程写了一遍; 然后在外面套了一个class, 那导致这个class 进行变更的原因就很多了.


# 设计模式

设计模式分为3类, 共23种.. 我们不会全学 因为有些用不到了,比如原型模式; 有些python本身就帮我们实现了, 比如迭代器模式..

-1- 创建型模式(5): 聚焦对象的创建.
-2- 结构型模式(7): 聚焦类之间的工作结构. 即 几个类组成一个什么结构? 这几个类如何在一起协同工作?
-3- 行为型模式(11): 聚焦类的方法/行为.


单一职责原则
创建型模式

← 单一职责原则 创建型模式→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式