接口倒置原则的最简化python实践

接口倒置原则的最简化python实践

在编程的SOLID 5大设计原则中,有人说最后一条接口倒置原则(Dependency Inverse Principle)是最重要的一条(也叫依赖倒置原则),因为他描述了代码如何通过抽象接口层实现松解耦和模块化,今天就来用python尝试实现以下最简化的接口倒置原则,体验一下接口倒置原则的道理。
简单来说,面向接口编程,实现依赖于接口,接口不要依赖于实现。(或者说细节依赖于抽象,抽象不要依赖与细节)。个人理解:尽可能减少每个模块对其它模块的依赖,尽可能只依赖其它模块的接口,而不是依赖于细节,这样我们修改细节后者增加细节的时候就不会破坏原来的大框架。有利于模块化和可扩展性。
以吃货喜欢的蛋糕作为例子,我们来写一个最简单的蛋糕类,这个蛋糕有两个属性,分别是:

  1. 形状属性:表示蛋糕的形状,比如三角形或者四边形
  2. 食材属性:表示蛋糕的材料组分,这里简化为某种脂状物 (cream) ,比如黄油cream或者芝士cream

蛋糕类的总体架构设计

在这里插入图片描述
这里我们把蛋糕的两个属性抽象为shape属性和cream属性,对应两个抽象接口类Shape类和Cream类,这两个接口类放在最底层(图中越往上依赖度越低对应的层级越低),这两个接口类不依赖于任何其它模块。对于形状Shape接口类,可以实现为具体的类比如三角形Triangle或者长方形Rectangle, 而Cream类则可以实现为具体的黄油Butter类或者芝士Cheese类。上面的类图可以分为两层:

  • 第0层:抽象接口类Shape和Cream, 这两个接口类放在最底层(上图中最上面的一层),无其它依赖,同时Shape和Cream之间互不相干
  • 第1层:同层的5个类(上图中同高度的5块)Cake, Triangle, Rectangle, Butter 和 Cheese之间完全独立,互不相干。
    • 其中蛋糕类依赖与前面的两个接口类Shape和Cream, 分别描述了蛋糕的形状属性和食材属性
    • 三角形类Triangle和长方形类Rectangle实现(继承)了作为抽象接口的形状类Shape, 使形状得到具象化
    • 黄油类Butter和芝士类Cheese实现(继承)了作为抽象接口的Cream类,使得脂状物Cream具象化为具体的黄油cream或者芝士cream.

这种设计方式实现了解耦合,提高了扩展性,如果我们想对Shape类进行扩展,提供更多形状,比如增加六边形形状,那么只需增加一个六边形类继承形状类,而形状类对应的代码无需修改,Cake类的代码也无需修改,因此扩展起来非常方便。
通常还有一个主模块需要依赖上述所有模块,比如会有一个主程序main, 这个main函数会依赖于上述的所有模块。这个main函数相当于给蛋糕注入灵魂,把芝士和三角形状赋给蛋糕,实际构造出一个三角形的芝士蛋糕对象,如下图所示:
在这里插入图片描述

代码的文件结构

这里用Python来实现上述的类图结构,对应的文件结构如下图所示:
在这里插入图片描述

  • 其中cream/文件夹中的cream_base.py 文件写了CreamBase抽象接口类,cream文件夹中的butter.py和cheese.py则分别继承实现了基类CreamBase;
  • shape/文件夹中的shape_base.py文件写了ShapeBase抽象接口类,文件夹中的另外两个文件triangle.py和rectangle.py则依赖了shape_base.py, 分别实现了Triangle类和Rectangle类来继承和实现ShapeBase类。
  • cake.py文件通过依赖 cream/cream_base.py 和 shape/shape_base.py 这两个文件来依赖CreamBase 和 ShapeBase 这两个接口类;但是对具体的实现类没有依赖,即没有依赖于具体的Butter, Cheese, Triangle, Rectangle等类。
  • main.py 对其它所有文件都有依赖。

组成类:形状类设计

形状类放在 shape/ 文件夹中,基类 shape_base.py文件内容为:

import abc


class ShapeBase(abc.ABC):

    @abc.abstractmethod
    def __init__(self):
        pass

    @abc.abstractmethod
    def cornersNumber(self):
        pass

其中通过 python 的abc模块定义了一个抽象接口类ShapeBase, 继承这个抽象类的其它类都需要实现里面的方法(其中conersNumber方法表示形状中有多少个角,比如三角形有3个角,四边形有4个角)。
继承ShapeBase的Trangle类写在 shape/triangle.py文件中,文件内容为:

from shape.shape_base import ShapeBase


class Triangle(ShapeBase):

    def __init__(self):
        pass

    def cornersNumber(self):
        return 3

继承ShapeBase的 Rectangle 类写在 shape/rectangle.py 文件中,内容为:

from shape.shape_base import ShapeBase


class Rectangle(ShapeBase):

    def __init__(self):
        pass

    def cornersNumber(self):
        return 4

_init_.py 文件为:

import sys

sys.path.append("./shape")

from triangle import Triangle
from rectangle import Rectangle

组成类:cream类设计

cream的基类放在文件 cream/cream_base.py 文件中,内容为:

import abc

class CreamBase(abc.ABC):
    @abc.abstractmethod
    def __init__(self):
        pass

    @abc.abstractmethod
    def color(self):
        pass

继承CreamBase 的 Butter 类放在 cream/butter.py 文件中,内容为:

from cream_base import CreamBase

class Butter(CreamBase):
    def __init__(self):
        pass

    def color(self):
        return "yellow"

继承CreamBase 的 Cheese 类放在 cream/cheese.py 文件中,内容为:

from cream_base import CreamBase

class Cheese(CreamBase):
    def __init__(self):
        pass

    def color(self):
        return "white"

_init_.py 文件为:

import sys
sys.path.append("./cream")

from cheese import Cheese
from butter import Butter

依赖接口类的蛋糕类

依赖接口类的蛋糕类放在 cake.py 中,内容为:

from cream.cream_base import CreamBase
from shape.shape_base import ShapeBase


class Cake(object):

    def __init__(self, shape: ShapeBase, cream: CreamBase):
        self._shape = shape
        self._cream = cream

    def cornersNumber(self):
        return self._shape.cornersNumber()

    def color(self):
        return self._cream.color()

运行的主程序 main.py 为:

from cake import Cake
from cream import *
from shape import *

if __name__ == "__main__":
    cake1 = Cake(Rectangle(), Butter())
    cake2 = Cake(Triangle(), Cheese())

    print(
        f"cake1.color() = {cake1.color()}, cake1.cornersNumber() = {cake1.cornersNumber()}"
    )
    print(
        f"cake2.color() = {cake2.color()}, cake2.cornersNumber() = {cake2.cornersNumber()}"
    )

主要思路和好处

时间所限,后面再来补充

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值