2017编程提高第7节课——面向对象设计(7)
LanyuanXiaoyao's Blog ヽ(✿゚▽゚)ノ

2017编程提高第7节课——面向对象设计(7)


讲解设计模式的思路

  • 传统思路
    • 动机、定义
    • 结构、分析
    • 案例
  • 先讲问题,然后讲一般的思路,最后引导出模式
    • Why → How

      神书

模式的分类

再次重申

  • 设计模式本质上是面向对象设计原则的体现
    • 针对接口编程而不是针对实现编程
    • 优先使用组合而不是继承
    • 发现变化并且封装变化
  • 学会设计模式,然后忘掉设计模式
    • 用设计模式的思想去编程

装饰者模式

Java Inputstream设计

  • Inpustream是基于字节的
    • 需求1: 直接读取Java 基本类型,而不是字节
    • 需求2: 需要支持缓冲
    • 需求3: 从Stream中读取的数据还可以放回Stream去
  • 解决办法1: 把这些功能加入到父类InputStream中
    • 不可行! 每个子类对数据的读取方法都不同, 父类无法知道每个子类的细节。
  • 解决办法2: 子类化
    • DataFileInputStream
    • BufferredFileInputStream
    • PushBackFileInputStream
    • 每个子类例如FileInputStream都需要创建3个子类

子类的爆炸问题

  • 根据排列组合, 仅仅FileInputStream就需要7个子类才能应对所有变化
    • Data + FileInputStream
    • Bufferred + FileInputStream
    • PushBack + FileInputStream
    • Bufferred + Data + FileInputStream
    • Bufferred + PushBack + FileInputStream
    • Data + PushBack + FileInputStream
    • Data + Bufferred + PushBack + FileInputStream

使用

new FileInputStream()
new BufferredInputStream(new FileInputStream(...)))
new DataInputStream(new BufferredInputStream(new FileInputStream(...)))
new BufferredInputStream(new DataInputStream(new FileInputStream(...)))

Decorator模式类图

代理模式

ATM 和 银行主机的通信

  • 细节,太多的细节, ATM无法专注于自己的业务
    • 网络
    • 协议
    • 安全
    • ……

把细节隐藏起来

从数据库获得User对象

增加缓存功能

增加权限检查

Proxy模式的类图

静态代理 vs 动态代理

  • 静态代理要求Proxy(UserManagerProxy, ArticleServiceProxy,  BankProxy)需要手工编码生成
  • 在很多时候需要动态给一个类增加行为
    • 例如增加事务,安全,日志等功能
  • 动态代理
    • Java 动态代理
    • CGLib ASM javassist

桥接模式

画图程序

  • 领导让你开发一个程序: 调用公司的图形库画出一个长方形来,你搜索了一下,发现公司有两个图形库可以使用:
    • Graphic Library 1 (GL1)
    • Graphic Library 2 (GL2)
  • 你的程序需要调用这两个图形库之一才能画长方形

两个图形库的差别

第一次设计

新需求

  • 领导要求支持一个新的形状: 圆形
  • 看来需要抽象: Shape
    • 让Rectangle 和 Circle 去继承

思考

  • 现在有两个图形库GL1, GL2 , 如果再来一个图形库GL3怎么样?
    • 需要给Rectangle 添加一个子类RectangleGL3
    • 需要给Circle 添加一个子类CircleGL3
    • 就会有6个子类  (3个图形库 * 2个形状)
  • 如果再加一个新的形状, 例如三角形
    • 就会有9个子类  (3个图形库 * 3个形状)
  • 子类爆炸问题出现了

解决办法: 识别变化

  • Shape 可以有多种多样
    • 长方形,圆形, 三角形…..
  • 图形库可以有多种多样
    • 图形库1, 图形库2, 图形库3…
  • 这是两个不同的维度! 应该让他们独立的变化
    • 形状已经有了抽象: Shape
    • 关键是对图形库做个抽象!

两个维度独立变化

Bridge 模式

Bridge 模式的使用场景

  • 当有两个正交的维度,这两个维度有一定的关联,但是还想独立变化的时候….
    • Shape   VS  Drawing
    • 文件格式 VS 文件序列化
    • 软件行为 VS 软件平台

Bridge 模式 类图

适配器模式

还是图形化的例子

适配一下

Adapter 模式类图

如何描述带有组合关系的树形结构

Composite 模式

适用场景:

  1. 想表达整体和部分的关系
  2. 调用方想忽略整体和部分的区别

Composite 变体

外观(Facade)模式

适用场景

  • 需要一个简单的接口去访问一个负责的系统
  • 如果一个系统非常复杂,难于理解
  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

Facade就在身边

围棋软件的例子

每个围棋棋子都是一个对象,属性有:

  1. 图标
  2. 位置

一个棋盘上的棋子很多,怎么设计才能尽可能的节省空间?

第一种思路

第二种思路

创建共享的Icon

使用

UML类图

Flyweight(享元) 模式

  • 以共享的方式高效地支持大量细粒度对象的重用
  • 共享的关键是区分内部状态(图标)和外部状态(位置)
    • 内部状态:可以共享,不随环境的变化而变化(图标)
    • 外部状态: 不可以共享,随环境变化而变化 (位置)

练习一下

Java String

Java Boolean, Integer,Long

作业

作业1 自制Builder 创建xml 字符串

作业2 从JDK中找出3个使用Singleton模式的类

参考链接:https://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns-in-javas-core-libraries?rq=1

作业3 实现装饰者

  • 需求1 如果是对外发送的邮件,需要在邮件的末尾增加上公司的声明:本邮件仅为个人观点,并不代表公司立场
  • 需求2 对邮件内容加密

作业4 实现Composite

作业5 实现Bridge


评论