把书读薄 | 《设计模式之美》学习导读 & 面向对象(上)

简介: 设计模式某些概念比较抽象,认真看完有时似懂非懂,往往没过多久就忘了,在实际设计与编码中,也不知道如何下手,所以需要落地,想办法加深理解,阅读开源项目,应用到项目中等等。本文是 学习导读(3讲)和面向对象(11讲) 的浓缩总结,二手知识加工难免有所纰漏,感兴趣有时间的可自行查阅原文,谢谢。

0x1、学习导读


  • 学习算法 → 是为了写出 高效 的代码;


  • 学习设计模式 → 是为了写出 高质量 (可扩展、可读、可维护)的代码;


很多开发仔写了很多年代码,Coding水平却没啥长进,原因是日常工作都是CV、修修补补的重复劳动。编写的代码大都止步于能用就好、能跑就行,能力自然停留在"会干活"的层面,只能算一个代码搬运的 熟练工


① 学习设计模式的理由


  • 应付面试


  • 少写烂代码 (写的代码维护费劲,增删功能,常常牵一发而动全身);


  • 提高复杂代码的设计和开发能力 (开发一个与业务无关的通用功能模块,力不从心,不止从何入手);


  • 读源码、学框架事半功倍 (琢磨不透作者的设计思路,一些明显的设计思路要花费很多时间才能参悟);


  • 职场发展做铺垫 (成为技术大牛的基本功,成为Leader指导培训新人,code review,招聘等);

② 如何判断代码质量的好坏


对一段代码的质量评价,常常具有很强的主观性,每个人的评判标准不一,这跟工程师自身经验有极大关系。


闷头写代码,在没 有人指导和阅读借鉴优秀源码 的情况下,很容易有种 自己的代码已经写得足够好 的错觉。


代码质量常用的几个评价标准


  • 可维护性 (Maintainability) → 较直观角度:Bug容易修复、修改添加功能轻松,则主观认为是易维护的;
  • 可读性 (Readability) → 好的验证手段:code review,别人可以轻松读懂你写的代码,说明代码可读性好;
  • 扩展性 (Extensibility) → 代码预留扩展点,添加功能直接插,无需大动干戈改动大量原始代码;
  • 灵活性 (Flexibility) → 一段代码易扩展、易复用或易用,可以称这段代码写得比较灵活;
  • 简洁性 (Simplicity) → 代码尽量写得简洁,逻辑清晰,符合KISS原则;
  • 可复用性 (Reusability) → 尽量减少重复代码的编写,复用已有代码;
  • 可测试性 (Testability) → 代码比较难写单元测试,基本上能说明代码设计得有问题;


如何才能写出搞质量代码


  • 面向对象设计思想 → 因其具有丰富的特性(封装、抽象、继承、多态),可实现很多复杂的设计思路,基础;
  • 设计原则 → 代码设计的经验总结,对某些场景下应用何种设计模式,有指导意义;
  • 设计模式 → 针对软件开发中常见的设计问题,总结出来的一套解决方案或设计思路;
  • 编码规范 → 主要解决代码可读性问题,更偏重代码细节,持续小重构依赖的理论基础;
  • 重构技巧 → 利用前面这四种理论,作为保持代码质量不下降的有效手段;


0x2、面向对象(OOP)


① 概念相关


面向过程编程 (OPP,Procedure Oriented Programming)


过程 为基础的编程范式/风格,主要关注 怎么做,即完成任务的具体细节,主要特点是数据与方法相互分离,流程化拼接一组顺序执行的方法,来操作数据完成某项功能。


面向对象编程 (OOP,Object Oriented Programming)


类或对象 为基础的编程范式/风格,主要关注 "谁来做",即完成任务的对象,将封装、抽象、继承、多态四个特性,作为代码设计与实现的基石。


面向过程编程语言


不支持类与对象语法概念,不支持丰富的面向对象特性,仅支持面向过程编程。


面向对象编程语言


支持类与对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言。另外,用面向对象语言编写的代码不一定就是面向对象编程风格的,也可能是面向过程的编程风格。


面向对象分析 (OOA,Object Oriented Analysis) 与 面向对象设计 (OOD,Object Oriented Design)


围绕着对象或类做需求分析与设计,前者搞清楚 做什么,后者搞清楚 怎么做,两个阶段的最终产出是 类的设计,包括程序被拆解成哪些类、每个类有哪些属性方法、类与类间如何交互等。而OOP就是将这两者的产出翻译成代码的过程。


OOP对比OPP编程有什么优势:


  • 大规模复杂程序开发,程序处理流程并非单一主线,而是错综复杂的网状结果,OOP更易应对;
  • OOP相比OPP,具有更多丰富特性,利用这些特性写出来的代码,更加易扩展、易复用、易维护;
  • OOP语言比起OPP语言,更加人性化、更加高级、更加智能 。


② 封装 (Encapsulation)


信息隐藏或数据访问保护,表现为:类暴露有限的访问接口(函数),授权外部仅能通过这些方式访问/修改内部信息或数据。


如Java中:使用 private 关键字设置访问限制,提供 gettersetter 供外部对数据仅限有限的操作和访问。


封装的意义


对类中属性的访问不加限制,可在任何代码中随意访问篡改,看似很灵活,却带来了 不可控问题。属性的修改逻辑可能散落在代码的各个角落,势必影响代码的可读性、可维护性。


一个封装的简单例子:


public class UserCredential {
    private String id;  // 用户ID
    private String key; // 用户Key
    private long lastVerifyTime;    // 上次校验时间
    private long verifyCount;    // 校验次数
    public UserCredential(String id, String key) {
        this.id = id;
        this.key = key;
    }
    public Long getLastVerifyTime() {
        return lastVerifyTime;
    }
    public void setLastVerifyTime(long lastVerifyTime) {
        this.lastVerifyTime = lastVerifyTime;
    }
    public void increaseVerifyCount() {
        verifyCount++;
    }
    public long getVerifyCount() {
        return verifyCount;
    }
}


代码解析:(对上面四个属性的访问进行了限制)


  • id、key → 创建用户凭证实例时就确定好,不该改动,所以不暴露访问或修改的方法;
  • lastVerifyTime → 每次验证凭证都更新这个值,有时也需要这个值,所以暴露getter和setter方法;
  • verifyCount → 每次校验都更新这个值,只会增且是+1,有时也需要这个值,所以暴露increase和getter方法;


Tips:设计实现类时,除非真的需要,否则,尽量不要给属性定义setter方法,除此之外,getter方法虽然相对setter安全写,但如果返回的是集合容器(如List),要注意防范集合内部数据被修改的危险。


封装带来的好处


减轻代码调用者对该类的学习负担(背后的业务细节),不必了解每个属性,可以放心地调用暴露的方法。


② 抽象 (Abstraction)


如何隐藏方法的具体实现,表现为:调用者只需关心方法提供的功能,而不需要知道功能是如何实现的。


在面向对象编程中,常利用编程语言提供的 接口类 (如Java中的Interface)或 抽象类 (如Java中的abstract) 这两种语法机制来实现抽象。


一个抽象的简单例子:


public interface IImageLoader {
    public void loadImage(String url);
}
public class MemoryImageLoader implements IImageLoader {
    @Override
    public void loadImage(String url) { ... }
}
public class DiskImageLoader implements IImageLoader {
    @Override
    public void loadImage(String url) { ... }
}


代码解析:


调用者在加载图片时,只需了解IImageLoader接口类暴露了什么方法,而不需要查看MemoryImageLoader和DiskImageLoader中的具体实现细节。


另外,抽象有时会被排除在面向对象的四大特性之外,原因是:


抽象这个特性,其实可以不借助接口类或抽象类这类特殊语法机制实现,类的方法通过编程语言中的 "函数" 语法实现。通过函数包裹具体实现逻辑,调用者无需研究具体的实现逻辑,通过函数名、注释或文档了解到函数功能,即可直接使用,这本身就是一种 抽象


抽象的意义


在面对复杂系统时,人脑能承受的信息复杂度是有限的,抽象这种只关注功能点不关注实现的设计思路,可以帮我们过滤掉很多非必要的信息。另外,很多设计原则也体现了抽象这种设计思想。


④ 继承 (Inheritance)


用来表示类之间的is-a关系,比如:猫是一种哺乳动物。根据遗传关系划分可以划分为:单继承和多继承。


单继承只能继承一个父类,多继承可以继承多个父类,比如猫既是哺乳动物,又是爬行动物。


为了实现继承这个特性,编程语言需要提供特殊的语法机制来支持,比如Java用extends,C++使用冒号(:)等。


有些编程语言只支持单继承,不支持多继承,比如Java,而有些编程语言都支持,比如C++。


继承的意义


代码复用,两个类具有相同属性或方法,将这部分代码抽取到父类中,让两个类继承父类,子类重用父类代码,避免代码重复。另外,应 避免过度使用继承,继承的层次过深过复杂,就会导致代码可读性、可维护性变差。


相关文章
|
5天前
|
设计模式 Java 关系型数据库
面向对象设计原则、设计模式与动态类型语言
面向对象设计原则、设计模式与动态类型语言
|
5天前
|
设计模式 前端开发 Java
设计模式之美学习(八):为何说要多用组合少用继承?如何决定该用组合还是继承?
设计模式之美学习(八):为何说要多用组合少用继承?如何决定该用组合还是继承?
|
6天前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
12 2
|
6天前
|
设计模式 安全 Java
设计模式学习心得之五种创建者模式(1)
设计模式学习心得之五种创建者模式(1)
7 0
|
6天前
|
设计模式 uml
设计模式学习心得之前置知识 UML图看法与六大原则(下)
设计模式学习心得之前置知识 UML图看法与六大原则(下)
9 2
|
6天前
|
设计模式 数据可视化 程序员
设计模式学习心得之前置知识 UML图看法与六大原则(上)
设计模式学习心得之前置知识 UML图看法与六大原则(上)
7 0
|
25天前
|
设计模式 存储 Java
JavaSE——面向对象高级二(2/4)-final关键字、常量、抽象类(认识抽象类、抽象类的好处、应用场景-模板方法设计模式)
JavaSE——面向对象高级二(2/4)-final关键字、常量、抽象类(认识抽象类、抽象类的好处、应用场景-模板方法设计模式)
14 0
|
2月前
|
设计模式 安全 Java
【JAVA学习之路 | 基础篇】单例设计模式
【JAVA学习之路 | 基础篇】单例设计模式
|
2月前
|
设计模式 存储 前端开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
|
2月前
|
设计模式 算法 架构师
【搞懂设计模式】设计模式与面向对象原则
【搞懂设计模式】设计模式与面向对象原则
23 1