张鹏 | 2021软件代码开发技术作业二 | 读书笔记----软件设计原则、设计模式
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology/ |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology/homework/11833 |
这个作业的目标 | 深入思考理解设计原则,及其优缺点 |
参考资料
Design patterns https://refactoring.guru/design-patterns ,转载遵循 Copyright。
软件设计的七大原则 https://blog.csdn.net/fengchao2016/article/details/54378113 ,转载遵循 CC 4.0 BY-SA。
装饰者模式 https://blog.2to.fun/post/Structure-Decoration/ ,转载遵循 CC 4.0 BY-SA。
参考使用Markdown语法标准:
GIthub Guides: https://guides.github.com/features/mastering-markdown/
Markdownlint: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
读书笔记
软件设计原则
都有哪些原则,以及原则的内涵
-
开闭原则 / Open-Closed Principle
一个软件应当对扩展开放
客户的需求是不稳定的,通过扩展已有的软件系统而不是通过修改软件系统来满足客户的需求,这样的软件系统就满足开-闭原则,即软件系统要有一定的灵活性和适应性。
-
里氏代换原则 / Liskov Substitution Principle
子类型必须能够替换它们的基类型。反过来的代换不成立。
当两个具体类关系违反里氏代换原则时,一种办法是抽象出一个基类,作为这两个类的父类,一种是应用组合聚合关系建立关系。不要为了使用某些类的方法(功能)而滥用继承。
对于A、B两个类,B由A派生,如果这种继承违反里氏替换原则,可以采用如下方法进行重构:将A、B的共同行为抽象出来,建立一个抽象类C,A和B都是C的派生类
-
依赖倒置原则 / Dependence Inversion Principle
具体要依赖于抽象,抽象不要依赖于具体。
要针对接口编程,不要针对实现编程。同样的,在处理类之间的耦合关系时,尽量使用抽象耦合的形式。
-
接口隔离原则 / Interface Segregation Principle
使用多个专门的接口比使用单一的总接口总要好。
从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小接口上的。过于臃肿的接口是对接口的污染。不应该强迫客户依赖于它们不用的方法。定制服务的例子,每一个接口应该是一种角色,不多不少,不干不该干的事,该干的事都要干。
-
合成/聚合复用原则 / Composite/Aggregate Reuse Principle (CAPR)
在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。
合成:一荣俱荣,一损俱损。
聚合:部分可以是整体的一部分,也可以脱离整体而存在。 -
迪米特法则 / Law of Demeter
一个对象应当对其它对象有尽可能少的了解。不要和陌生人说话。
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另外一个类的某一个方法,可以通过第三者转发这个调用。
-
抽象类原则
抽象类不会有实例,一般作为父类为子类继承,一般包含这个系的共同属性和方法。
设计模式
什么是设计模式?
设计模式是软件设计中常见的典型解决方案。它们就够根据需求进行调整的预制蓝图,可用于解决代码中反复出现的问题。(@Refactoring.Guru)
设计模式与方法或库的使用方式不同,我们很难在自己的程序中套用某个设计模式。模式并不是一段特定的代码,而是解决问题的一般性概念。我们可以根据模式来实现复合自己程序世纪所需要的解决方案。
大部分模式都有正规的描述方式,以便在不同情况下使用。模式通常包括以下部分:
-
意图部分简单描述问题和解决方案。
-
动机部分将进一步解释问题并说明模式会如何提供解决方案。
-
结构部分展示模式各个部分和它们之间的关系。
设计模式的优缺点
设计模式是针对软件设计中常见问题的工具箱, 其中的工具就是各种经过实践验证的解决方案。 即使你从未遇到过这些问题, 了解模式仍然非常有用, 因为它能指导你如何使用面向对象的设计原则来解决各种问题。
设计模式自从被发明后一直饱受争议。例如很多人认为模式是一种针对不完善编程语言的不妥善的解决方案。
通常当所选编程语言或技术缺少必要的抽象功能时, 人们才需要设计模式。 在这种情况下, 模式是一种可为语言提供更优功能的蹩脚解决方案。例如, 策略模式在绝大部分现代编程语言中可以简单地使用匿名 (lambda) 函数来实现。
比较流传的设计模式方案
-
创造型模式
工厂方法 / 抽象工厂 / 生成器 / 原型 / 单例
-
结构型模式
适配器 / 桥接 / 组合 / 装饰 / 外观 / 享元 / 代理
-
行为模式
责任链 / 命令 / 迭代器 / 中介者 / 备忘录 / 观察者 / 状态 / 策略 / 模版方法 / 访问者
心得体会
在实际学习中,我没有刻意学习过软件设计原则,但是大体上遵循低耦合,高内聚的开发思想。在我实际开发的项目中我比较明确感受到的几个原则有:OCP、DIP、ISP以及CARP。
我重点感受的是设计模式,在我的博客也曾讨论过 装饰模式。
常见的装饰者模块结构
# 对装饰模式的简单应用
from functools import wraps
def login_check(func):
"""
Decorator
check whether user is logged in
:param func
:return wrapper
"""
@wraps(func)
def wrapper(*args, **kwargs):
if args[0].status != "login":
print("User hasn't logged in yet!")
else:
return func(*args, **kwargs)
return wrapper
class Visitor(object):
def __init__(self, status) -> None:
self.status = status
# decorate this method
@login_check
def access_allow(self):
print("User now has login. Access is allowed")
if __name__ == "__main__":
print('>>> set status login, is result')
visitor = Visitor('login')
visitor.access_allow()
print('>>> set status not login, below is result')
visitor = Visitor('visitor')
visitor.access_allow()
在这里我实现了模块化的登录检查,可以简化代码开发过程中的代码复用,加快软件开发的流程。
我在大二的《操作系统》的课程设计仿照 Linux 的文件模型选做了 文件管理系统 (下称FSM,File System Manager),在大三的第一学期也是重新该 FSM 进行优化,其中大量采用了装饰者模式。
例如模块化对文件的增、删、改、查,模块化兼容读取不同格式的外部文件。
不得不承认最开始的代码开发是痛苦的,结构框架也是随着时间逐渐完善的。但是随着框架的逐渐完善,大量采用该模式也给我带来了更高的可维护性,让我可以专心负责某一代码块,而不用顾及改动对上下文的影响。
在我看来,开发模式不一定能简化代码,在大多数情况下反而会大大增加软件开发的工作量、代码量,但是对于一个长期维护的软件生态来说,它很值得这些付出,它意味着日后维护更低的成本,将获得更高的开发收益。