Coding in life...

a litter inspiration


  • Home

  • Categories

  • Archives

  • Tags

  • Search

敏捷软件开发-第三周

Posted on 2019-03-15 | In alige PPP

第二部分 敏捷设计

什么是敏捷设计

单一职责原则(SRP)

就一个类而言,应该仅有一个引起它变化的原因

什么是职责:

- 在SRP中,我们把职责定义为“变化的原因”,如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。

开放-封闭原则(OCP)

软件实体(类,模块,函数)应该是可以扩展的,但是不可修改的

描述:
遵循开发-封闭原则设计出的模块具有两个主要的特征。

  1. 对于扩展是开发的 (open for extension)

    • 我们可以改变模块的功能
  2. 对于更改是封闭的(Close for modification)

    • 对模块的行为进行扩展,不必改动模块的源代码或者二进制代码。模块的二进制可执行版本,都无需改动

关键是抽象:
可以创建出固定能够描述一组任意个可能行为的抽象体。这个抽象体就是抽象基类。而这一组任意个可能的行为则表现为可能的派生类。

模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体。所以它对于更改可以是改变的。同时从这个抽象体派生,也可以扩展此模块的行为。

Liskov替换原则(LSP)

对于LSP的解释:
子类型(subtype)必须能够替换掉它们的基类型(base type)

依赖倒置原则(DIP)

  1. 高层模块不应该依赖于低层模块。二者都应该依赖于抽象

  2. 抽象不应该依赖于细节。细节应该依赖于抽象。

依赖于抽象:

1. 任何变量都不应该持有一个指向具体类的引用
2. 任何类都不应该从具体类从派生
3. 任何方法都不应该覆写它的任何基类中的已经实现了的方法。

如果一个具体类不太会改变。并且也不会创建其他类似的派生类,那么依赖于它并不会造成损害

接口隔离原则(ISP)

敏捷软件开发-第一周

Posted on 2019-03-03 | In alige PPP

第一部分 敏捷开发

第一章 敏捷实践

  • 敏捷软件开发

    1. 个体和交互 -》 过程和工具

      • 可以从一个小工具开始使用,直到不合适之后,再进行更换
      • 不要认为,更大,更好的工具可以自动帮你做的更好。通常它们的阻碍大于帮助
      • 记住:团队的构建大于环境的构建
    2. 可以工作的软件 -》面面俱到的文档

      • 没有文档的的软件是一种灾难。代码不是传达系统原理和结构的理想媒介
      • 团队更需要编制易于阅读的文档,来对系统及其设计决策的依据进行描述
      • 过多的文档比过少的文档更可怕 时间、误导
      • 给新成员传授知识方面,最好的两份文档是代码和团队

        • 代码是惟一没有二义性的信息源
        • 团队成员的头脑中,保存着时常变化的系统脉络图(road map)。人和人之间的交互是把这份脉络图传授给他人的最快,最有效的方式
      • 直到迫切需要并且意义重大时,才来编写文档

    3. 客户合作 -》合同谈判

      • 不能像订购日用品一样来订购软件。你不能够仅仅写一份关于你想要的软件的描述,然后就让人在固定的时间内以固定的价格去开发它。所有用这种方式来对待项目的尝试都以失败而告终。
      • 成功的项目需要有序,频繁的客户反馈
      • 哪些为开发团队和客户的协同工作方式提供指导的合同才是最好的合同
      • 成功的关键在于和客户之间真诚的协作,并且合同指导了这种协作,而不是试图去规定项目范围的细节和固定成本下的进度
    4. 响应变化 -》 遵循计划

      • 响应变化的能力常常决定这一个软件项目的成败。当我们构建计划是,应确保计划是灵活的并且易于适应商务和技术方面的变化
      • 较好的做计划的方式是,每两周做一个详细的计划,为下三个月做粗略的计划,再以后就做即为粗糙的计划

  • 原则

    1. 我们最优先要做的是通过尽早的,持续的交付有价值的软件来使客户满意
    2. 即使到了开发的后期,也欢迎改需求,敏捷过程利用变化来为客户创造竞争优势
    3. 经常性的交付可以工作的软件,交付的间隔可以是几周也可以是几个月,交付的时间越短越好
    4. 项目开发期间,业务人员和开发人员必须天天在一起工作
    5. 围绕被激励起来的个人来构建项目,给他们提供所需要的 环境和支持,并且信任他们能完成工作
    6. 在团队内部,最具有效果并且富有效率的传递信息的方法,就是面对面的交谈
    7. 工作的软件是首要的进度度量标准
    8. 敏捷过程提倡可持续的开发速度。责任人,开发者和用户应该能够保持一个长期的,恒定的开发速度
    9. 不断的关注优秀的技能和好的设计会增强敏捷能力
    10. 简单–使未完成的工作最大化的艺术–是根本的
    11. 最好的架构,需求和设计出自于自组织的团队
    12. 每隔一定时间,团队会在如何才能更有效的工作方面进行反省,然后相应地对自己的行为进行调整

第二章 极限编程概述

极限编程实践

  • 概述:极限编程(eXtreme Programming, 简称XP)

    • 是敏捷方法中最著名的一个,它由一系列简单却互相依赖的实践组成。这些实践结合在一起形成了一个胜于部分结合的整体
  • 客户作为团队成员

    • 谁是客户?XP团队中的客户是指定义产品的特性并排列这些特性优秀级的人或者团队
  • 用户素材

    • 为了进行项目计划,必须要知道和项目需求有关的内容,但是却无需知道的太多。对于做计划而言,了解需求只需要做到能够估算它的程度就足够了
    • 在XP中,我们和客户反复讨论,以获取对于需求细节的理解,但是不去捕获哪些细节。我们更愿意在索引卡片上写下一些我们认可的词语,这些可以提醒我们记起这次交谈。
    • 开发人员在该卡片上写下对应于卡片上需求的估算。估算是基于和客户进行交谈期间所得到的对于细节的理解进行的
    • 用户素材(user stories)就是正在进行的关于需求谈话的助记符。它是一个计划工具,客户可以使用它并根据它的优秀级和估算代价来安排实现该需求的时间。
  • 短交付周期

    • 迭代计划
    • 发布计划
  • 验收测试

  • 结对编程
  • 测试驱动的开发方法

    • 编写所有产品代码的目的都是为了使失败的单元测试能够通过。首先编写一个单元测试,由于它要测试的功能还不存在,所以它会运行失败,然后编写使测试通过
    • 编写测试用例和代码之间的更迭速度是很快的,基本上几分钟左右,测试用例和代码共同演化,其中测试用例循序渐进地对代码的编写进行指导
    • 作为结果,一个非常完美的测试用列集就和代码一起发展起来,程序员可以使用这些测试来检查程序是否正确工作。-》非常有利于重构
    • 当为了使测试用例通过而编写代码时,这样的代码就被定义为可测试的代码。这样做会强烈地激发你去解除各个模块的耦合,这样能够独立地对它们进行测试。
  • 集体所有权

  • 持续集成
  • 可持续的开发速度
  • 开发的工作空间
  • 计划游戏
  • 简单的设计

    • 团队使他们的

      -计划游戏的本质是划分业务人员和开发人员之间的职责,业务人员(客户)决定特性(feature)的重要性。开发人员决定实现一个特性所花费的代价

  • 重构

    第三章 计划

    第四章 测试

    第五章 重构

第12章-并发编程

Posted on 2019-02-17 | In 《深入理解计算机系统》

前言

如果逻辑控制流在时间上重叠,那么它们就是并发的(concurrent)。这种常见的现象称为并发(concurrency )

使用应用级并发的应用程序称为并发程序(concurrent program)。现代操作系统提供了三种基本的构造并发程序的方法:

  • 进程

    • 用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护。因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显示的进程间通信(interprocess communication, IPC)机制。
  • I/O多路复用

    • 在这种形式的并发编程中,应用程序在一个进程的上下文中显示地调度它们自己的逻辑流。逻辑流被模型化为状态机,数据到达文件描述符后,主程序显示地从一个状态转换到另一个状态。因为程序是一个单独的进程,所以所有的流都共享同一个地址空间
  • 线程

    • 线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度。你可以把线程看成是其他两种方式的混合体,像进程流一样由内核进行调度,而像I/O多路复用流一样共享同一个虚拟地址空间。

12.1 基于进程的并发编程

12.2 基于I/O多路复用的并发编程

12.3 基于线程的并发编程

12.4 多线程程序中的共享变量

12.5 用信号量同步线程

12.6 使用线程提供并行性

12.7 其他并发问题

12.8 小结

第11章-网络编程

Posted on 2019-01-15 | In 《深入理解计算机系统》

前言

11.1 客户端-服务器编程模型

每个网络应用都是基于客户端-服务器模型的。

采用这个模型

  • 一个应用是由一个服务器进程和一个或者多个客户端进程组成。
  • 服务器管理某种资源,并且通过操作这种资源来为它的客户端提供某种服务。

客户端-服务器模型中的基本操作是事物(transaction)。一个客户端-服务器事物

  1. 当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务
  2. 服务器收到请求后,解释它,并以适当的方式操作它的资源、
  3. 服务器给客户端发送一个响应,并等待下一个请求。
  4. 客户端收到响应并处理它。

认识到客户端和服务端是进程,而不是常提到的机器或者主机,这是非常重要的。

一台主机可以同时运行许多不同的客户端和服务器,而且一个客户端和服务器的事物可以在同一台或是不同的主机上

11.2 网络

客户端和服务器通常运行在不同的主机上,并且通过计算机网络的硬件和软件资源来通讯。

对主机而言,网络只是一种I/O设备,是数据源和数据接收方。

  • 从网络上接收到的数据从适配器经过I/O和内存总线复制到内存,通常是通过DMA传送。

物理上而言,网络是一个按照地理远近组成的层次系统。最底层是LAN(local area network,局域网),在一个建筑或者校园范围内。
迄今为止,最流行的局域网技术是以太网(Ethernet)

  • 一个以太网段(Ethernet segment)包括一些电缆(通常是双绞线)和一个集成器的小盒子
  • 一端连接到主机的适配器,另一端连接到集线器的一个端口上。
  • 集线器不加分辨地将从一个端口上收到的每个位复制到其他所有的端口上。因此,每台主机都能看到每个位

每个以太网适配器都有一个全球唯一的48位地址,它存储在这个适配器的非易失性存储器上。一台主机可以发送一段位(称为帧(frame))到这个网段内的其他任何主机。每个帧包括一些固定数量的头部(header)位,用来标识此帧的源和目的地址以及此帧的长度,此后紧随的就是数据位的有效载荷(payload)。每个主机适配器都能看到这个帧,但是只有目的主机实际读取它。

使用一些电缆和叫做网桥(bridge)的小盒子,多个以太网段可以连接成较大的局域网,称为桥接以太网(bridge Ethernet)

11.3 全球网络IP因特网

11.4 套接字接口

11.5 Web服务器

11.6 TINY Web服务器

11.7 小结

第十章-系统级I/O

Posted on 2019-01-08 | In 《深入理解计算机系统》

前言

输入/输出(I/O)是主存和外部设备(列如磁盘驱动器、终端和网络)之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备

10.1 Unix I/O

一个Linux文件就是一个m个字节的序列。

所有的I/O设备(例如网络、磁盘和终端)都被模型化为文件,而所有的输入和输出都被当作对相应文件的读和写来执行。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单、低级的应用程序接口,称为Unix I/O,这使得所有的输入和输出都能以一种统一且一致的方式来执行:

  • 打开文件

    • 一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备。
    • 内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标识这个文件。内核记录有关这个打开文件的所有信息。应用程序只需记录这个描述符
  • Linux Shell 创建的每个进程开始时都有三个打开的文件:

    • 标准的输入(描述符为0)、
    • 标准输出(描述为1)
    • 标准错误(描述符为2)
  • 改变当前的文件位置

    • 对于每个打开的文件,内核保持着一个文件位置k,初始为0。
    • 这个文件位置是从文件开头起始的字节偏移量
  • 读写文件

    • 一个读操作就是从文件复制n>0个字节到内存,从当前位置k开始,然后将k增加到k+n。
    • 给定一个大小为m字节的文件,当k>=m时执行

10.2 文件

每个Linux文件都有一个类型(type)来表明他在系统中的角色:

  • 普通文件(regular file)

    • 包含任意数据
    • 应用程序常常要区分文本文件(text file)和二进制文件(binary file)
    • 对内核而言,没有区别
  • 目录(directory)

    • 是包含一组链接(link)的文件,其中每个链接都讲一个文件名(filename)映射到一个文件。
    • 这个文件可能是另一个目录
    • 每个目录至少包含有2个条目 1。 ‘.’ 2. ‘..’
  • 套接字(socket)

    • 是用来与另一个进程进行跨网络通宵的文件。

10.3 打开和关闭文件

10.4 读和写文件

10.5 用RIO包健壮地读写

10.6 读取文件元数据

10.7 读取目录内容

10.8 共享文件

文件共享概念。
内核用三个相关的数据结构来表示打开的文件

  • 描述符表(descriptor table)

    • 每个进程都有它独立的描述符表,它的表项是由进程打开的文件描述符来索引的。每个打开的描述符表项指向文件表中的一个表项
  • 文件表(file table)

    • 打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。每个文件表的表项组成(针对我们的目的)包括当前的文件位置、引用计数(reference count)(即当前指向该表项的描述符表项数),以及一个指向v-node表中对应表项的指针。
    • 关闭一个描述符会减少相应的文件表项中的引用计数。内核不会删除这个文件表表项,直到它的引用计数为0
  • v-node表(v-node table)

    • 同文件表一样,所有的进程共享这张v-node表。

10.9 I/O重定向

10.10 标准I/O

标准I/O库将一个打开的文件模型化为一个流。

10.11 综合:我该使用那些I/O函数

10.12 小结

第九章-虚拟内存

Posted on 2019-01-04 | In 《深入理解计算机系统》

前言

为了更加有效的管理内存并且少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟内存(VM)

  • 虚拟内存

    • 是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间。
  • 虚拟内存提供了三个重要的能力:

    1. 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,高效的使用主存
    2. 它为每个进程提供了一致的地址空间,从而简化了内存管理
    3. 它保护了每个进程的地址空间不被其它进程破坏

malloc程序,动态内存分配器

9.1 物理和虚拟寻址

计算机系统的主存被组织成为一个由M个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址(Physical address,PA)

  • 第一个字节的地址为0
  • CPU访问内存最自然的方式就是使用物理地址。我们把这种方式成为物理寻址

现代处理器使用的是一种称为虚拟寻址(virtual addressing)的寻址形式。

使用虚拟寻址,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址

将一个虚拟地址转换成物理地址的任务叫做地址翻译。就像异常处理一样,地址翻译需要CPU硬件和操作系统之间的紧密合作。

CPU芯片上叫做内存管理单元(Memory Managerment Unit)的专用硬件,利用存放在主存中的查询来动态翻译虚拟地址,该表的内容由操作系统管理

9.2 地址空间

9.3 虚拟内存作为缓存的工具

概念上,虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一的虚拟地址,作为到数组的索引。

磁盘上数组的内容被缓存在主存中。

  • VM系统通过将虚拟内存分割为称为虚拟页(Virtual Page,VP)的大小固定的块
  • 物理内存被分割为物理页(Physical Page,PP),大小和虚拟页一致,被称为页帧(Page Frame)

在任意时刻,虚拟页面的集合都分为三个不想交的子集。

  • 未分配的
  • 缓存的
  • 未缓存的

9.4 虚拟内存作为内存管理的工具

9.5 虚拟内存作为内存保护的工具

9.6 地址翻译

9.7 案例研究

9.8 内存映射

Linux通过将一个虚拟内存区域与一个磁盘上的对象(object)关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)。虚拟内存区域可以映射到两种类型的对象中的一种。

9.9 动态内存分配

9.10 垃圾收集

垃圾收集器(garbage collector)是一种动态内存分配器,它自动释放程序不再需要的已分配块。这些块被称为垃圾(garbage)。

自动回收堆存储的过程叫做垃圾收集(garbage)。在一个支持垃圾收集的系统中,应用显示分配堆块,但是从不显示地释放它们。

垃圾收集器将内存视为一张有向可达图(reachability graph),该图的节点被分成一组根节点(root node)和一组堆节点(heap node),每个堆节点对应于堆中的一个已分配块。

9.11 C程序中常见的与内存有关的错误

9.12 小结

第八章-异常控制流

Posted on 2019-01-01 | In 《深入理解计算机系统》

前言

  • 处理器的控制序列:

从给处理器加电开始,直到你断电为止,程序计数器假设一个值的序列

a0,a1,...an-1

其中,每个ak是某个相应的指令Ik的地址。每次从ak到ak+1的过度称为控制转移(control transfer)。这样的控制转移序列叫做处理器的控制流(flow of control 或 control flow)

  • 最简单的一种控制流

    • 是一个“平滑的”序列,其中每个Ik和Ik+1在内存中都是相邻的。
  • 平滑流的突变

  • 异常控制流(Exception control flow)

    • 现代系统通过使控制流发生突变来对这些情况做出反应。
    • 异常控制流发生在计算机系统的各个层次
      • 硬件层
      • 操作系统层
      • 应用层

理解ECF,有很多原因:

  1. 理解重要的系统概念
  2. 理解应用程序是如何与操作系统交互的
  3. 编写有趣的应用程序
  4. 理解并发
  5. 理解软件异常如何工作

8.1 异常

异常是异常控制流的一种形式,它一部分由硬件实现,一部分由操作系统实现

异常(exception)就是控制流中的突变,用来响应处理器状态中的某些变化

在处理器中,状态被编码为不同的信号和位,状态的变化称之为事件(event)

在任何情况下,当处理器检测到有事件发生时,它就会通过一张叫做异常表(exception table)的跳转表,进行一个间接过程调用(异常),到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序(exception handler))。当异常处理程序完成处理后,根据引起异常的事件的类型,会发生以下3种情况中的一种:

  1. 处理程序将控制返回给当前指令Icurr,即当事件发生时正在执行的指令
  2. 处理程序将控制流返回给Inext,如果没有发生异常将会执行的下一条指令
  3. 处理程序终止被中断的程序。

8.1.2 异常的类别
异常可以分为四类:

  • 中断(interrupt)

    • 原因: 来自I/O设备的信号
    • 异步
    • 返回的行为:总是返回到下一条指令
  • 陷阱(trap)

    • 原因:有意的异常
    • 同步
    • 总是返回到下一条指令
  • 故障(fault)

    • 潜在可恢复的错误
    • 同步
    • 可能返回到当前指令
  • 终止(abort)

    • 不可恢复的错误
    • 同步
    • 不会返回

8.2 进程

异常时允许操作系统内核提供进程(process)概念的基本构造块

进程的经典定义就是一个执行中程序的实例。系统中每个程序都运行在某个进程的上下文(context)中。上下文是由程序运行所需的状态组成的。

这个状态包括存放在内存中的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。

进程提供给应用程序的抽象

  • 一个独立的逻辑控制流

    • 它提供一个假象,好像我们的程序独占地使用处理器
  • 一个独立的地址空间

    • 它提供一个假象,好像我们的程序独占地使用内存系统

8.2.2 并发流
一个逻辑流的执行时间上与另一个流重叠,称为并发流(concurrent flow),这两个流被称为并发地运行

多个流并发地执行的一般现象被称为并发(concurrency)。一个进程和其它进程轮流运行的概念称为多任务(multitasking)。一个进程执行它的控制流的一部分的每一时间段叫做时间片(time slice)
并行流是并发流的一个真子集。

如果两个流并发地运行在不同的处理器核或者计算机上,那么我们称它们为并行流(parallel flow),它们并行的运行(running in parallel),且并行地执行(parallel execution)

8.2.3 私有地址空间
进程也为每个地址空间提供一种假象,好像它独占地使用系统地址空间。进程为每个程序提供它自己的私有地址空间。

  • 一般而言,和这个空间中某个地址相关联的那个内存字节是不能被其他进程读或者写的,从这个意义上说,这个地址空间是私有的。
  • 私有地址空间,内容都不相同,但是每个这样的空间都有相同的通用结构。

地址空间底部是保留给用户程序的,包括通常的代码、数据、堆和栈段。

  • 代码段总是从地址0x400000开始。地址空间顶部保留给内核(操作系统常驻内存的部分)。地址空间的这个部分包含内核在代表进程执行时(比如当应用程序执行系统调用时)使用的代码、数据和栈

8.2.4 用户模式和内核模式

为了使操作系统内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及它可以访问的地址空间范围

处理器通常是用某个控制寄存器中的一个模式位(mode bit)来提供这种功能的,该寄存器描述了当前进程享有的特权。当设置了模式位时,进程就运行在内核模式中(有时也叫做超级用户模式)。一个运行在内核模式的进程可以执行指令集中的任何指令,并且可以访问系统中的任何内存位置

没有设置模式位时,进程就运行在用户模式中。用户模式中的进程不允许执行特权指令(privileged instruction)

运行应用程序代码的进程初始时是在用户模式中的。进程从用户模式变为内核模式的唯一方法是通过诸如中断、故障或者陷入系统调用这样的异常。当异常发生时,控制传递到异常处理程序,处理器将模式从用户模式改为内核模式。当返回时,又变回来。

8.2.5 上下文切换

操作系统内核使用一种称为上下文切换(context switch)的较高形式的异常控制流来实现多任务。上下文切换机制是建立在较低异常机制之上的。

在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占了的进程。这种决策叫做调度(scheduling),是由内核中称为调度器(scheduler)的代码处理的。

8.3 系统调用错误处理

8.4 进程控制

从程序员的角度,我们可以认为进程总是处于下面三种状态之一:

  • 运行

    • 进程要么在CPU上执行,要么在等待被执行且最终会被内核调度
  • 停止

    • 进程的执行被挂起(suspended),且不会被调度。
  • 终止

    • 进程永远地停止了。进程会因为三种原因终止

      • 收到一个信号,该信号默认行为是终止进程
      • 从主程序返回
      • 调用exit函数

程序与进程

程序是一堆代码和数据;程序可以作为目标文件存在于磁盘上,或者作为段存在于地址空间中。

进程是执行中程序的一个具体的实例;程序总是运行在某个进程的上下文中

8.5 信号

一种更高层的软件形式的异常,称为Linux异常,它允许进程和内核中断其他进程。

一个信号就是一条小消息。它通知进程系统中发生了一个某种类型的事件

8.5.1 信号术语
传送一个信号到目的进程是由两个不同的步骤组成的:

  1. 发送信号

    • 内核通过更新目的进程上下文中的某个状态,发送(传递)一个信号目的进程
  2. 接收信号

8.6 非本地跳转

8.7 操作进程的工具

8.8 小结

设计模式01

Posted on 2018-12-18

阶段一:

  • 有一个Duck的超类。里面包含了一些正常的方法。

需 求:需要给鸭子们实现一个会飞的动作。fly()

第一次实现:在父类中进行实现fly()

结果: 对于部分子类来说,没有必要的行为这个行为,比如橡皮鸭子不应该有fly()方法。这个地方即使重写了此方法。用doNothing()什么都不做。还是不好算是垃圾代码。

阶段二:

我们应该把变化的部分,和不变的部分进行区分。

比如fly()方法不应该放入duck类中。我们可以将其抽取为接口flyable(),将其和duck类进行解耦。当部分subDuck类需要实现fly()方法时,直接实现就行。这样就让比如橡皮鸭这种子类,就可以脱离部分垃圾代码了。

问题:解耦确实解耦,目的也达到了,但是有个问题。代码将不能复用,每个实现该fly()接口的,如果方法实现都是一样的,则会出现每实现一次该接口,就得重写该方法,即便逻辑未变。

解决方法:面向接口编程。用一个更加具体的接口去实现fly()接口,这种类称为行为类。

阶段三:

这个地方主要在于面向接口编程。千万别面向继承编程。充分利用多态的功能。

比如有一个animate超类 ,有dog 和 cat子类。以下为演进过程

  • Dog a = new Dog();
  • Animate b = new Dog();
  • Animate c = getAnimate();

设计原则

  1. 区分不变的和变的 。 封装变化的。

MySQL必知必会11-14章

Posted on 2018-12-18 | In 《MySQL必知必会》

第11章 使用数据处理函数

函数:

SQL支持利用函数来处理数据。函数一般是在数据上执行的,它给数据的转换和处理提供了方便

函数没有SQL的可移植性强

能运行在多个系统上的代码称为可移植的(portable)

  • 文本处理函数
  • 日期和时间处理函数
  • 数值处理函数

第12章 汇总数据

我们经常需要汇总数据而不用把它们实际检索出来,为此聚集函数

聚集函数(aggregate function)

运行在行组上,计算和返回单个值的函数
  • AVG()

    • 只用于单个列
    • AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参数给出。为了获得多个列的平均值,必须使用多个AVG()函数
  • COUNT()
  • MAX()
  • MIN()
  • SUM()

NULL值 AVG()函数忽略列值为NULL的行 (这几个都忽略)


第13章 分组数据

注意事项:

  • group by 子句可以包含任意数目的列。

    • 这使得能对分组进行嵌套
  • group by 如果在子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从单个列中取回数据)

  • group by子句中列出的每个列都必须是检索列或有效的表达式(但不能是集聚函数)。如果在select 中使用表达式,则必须在group by子句中指定相同的表达式。不能使用别名。
  • 除集聚计算语句外,select语句中的每个列都必须在groub by子句中指定相同的表达式。不能使用别名
  • 除集聚计算语句外,select语句中的每个列都必须在group by子句中给出
  • 如果分组列中具有null值,则null将作为一个分组返回。如果列中有多行null值,它们将分为一组
  • group by子句必须出现在where子句后,order by子句之前。

过滤分组

where子句只能过滤行,而不能过滤分组 。Having子句可以过滤分组,

Having非常类似于where,事实上,目前为止所学过的所有类型的WHERE子句都可以用having子句来代替。

唯一的区别是where过滤行,having过滤的是分组。
还可以这么理解:where在数据分组前进行过滤,having在数据分组后进行过滤。where排除的行不包括在分组中。

having支持所有where操作符

SELECT子句顺序
  1. select
  2. from
  3. where

MySQL必知必会4-10章

Posted on 2018-12-17 | In 《MySQL必知必会》

第5章 排序检索数据

子句(clause)

  • SQL语句由子句构成,有些子句是必需的,而有的是可选的。一个子句通常由一个关键字和所提供的数据组成。

    • 子句的例子有:SELECT语句的FROM子句

谓词(predicate)

  • 操作符何时不是操作符?答案是在它作为谓词时,从技术上来说,LIKE是谓词而不是操作符。

区分大小写

  • 根据MySQL的配置方式,搜索可以是区分大小写的。

第9章 用正则表达式进行搜索

正则表达式是用来匹配文本的特殊的串(字符集合)

为了匹配特殊字符

  • 必须使用 \

    • 多数正则表达式实现使用单个反斜杠转义特殊字符,以便能使用这些字符本身。但MySQL要求两个反斜杠(MySQL自己解释一个,正则表达式库解释另一个)

重复元字符

  • *

    • 0个或多个匹配
  • +

    • 1个或多个匹配
    • 等于 {1,}
  • ?

    • 0个或1个匹配
    • 等于 {0,1}
  • {n}

    • 指定数目的匹配
  • {n,}

    • 不少于指定数目的匹配
  • {n,m}

    • 匹配数目的范围(m不超过255)

定位元字符

  • ^

    • 文本的开始
    • ^有双重用途
      • 在集合中(用[和]定义),用它来否定该集合
      • 否则,用来指定串的开始处。
  • $

    • 文本的结尾
  • [[:<:]]

    • 词的开始
  • [[:>:]]

    • 词的结尾

第10章 创建计算字段

  • 字段(field)

    • 基本上与列(column)的意思相同,经常互换使用,不过数据库例一般称为列,而术语字段通常用在计算字段的连接上。
    • 要知道:只有数据库知道select语句中哪些列是实际的表列,哪些列是计算字段。从客户机(如应用程序)的角度来看,计算字段的数据是以与其他列的数据相同的方式返回的。

这个还能进行算数计算的哦!

  • 别名(alias)

    • 别名(alias)是一个字段或值的替换名。别名用AS关键字赋予。
    • 导出列: 别名有时也称为导出列(derived column),不管称为什么,它们所代表的都是相同的东西。
12…4
luowen

luowen

Blogging is a little fun

37 posts
16 categories
16 tags
© 2019 luowen
Powered by Hexo
Theme - NexT.Mist
访问人数 人 总访问量 次