一、基础知识
统一建模语言(UML)基础知识
通过图形符号与文字来对系统进行建模
视图
用户视图
结构视图
行为视图
实现视图
环境视图
图
用例图
类图,对象图,包图,组合结构图
状态图,活动图,顺序图,通信图,定时图,交互概览图
组件图
部署图
用例图(需求分析)
类图(数据&行为)
静态结构,描述不同类与其之间的行为
模型元素(事物&事物之间的联系)
每一个模型元素都与一个图形元素相对应
同一个模型元素可以在不同的UML图中使用
面向对象设计原则
可维护性&可复用性
是一种指导性原则(非强制)
单一职责原则(高内聚、低耦合):每个对象只有单一职责
开闭原则:扩展性方面应该开放的,而在更改性方面应该是封闭的,软件实体应尽量在不改变原有代码的情况下扩展
关键是抽象化、稳定的抽象层+灵活的具体层
里氏代换原则:所有应用基类的地方必须能透明地使用其子类的对象(将一个基类替换为它的子类对象,程序不会产生任何错误与异常)
依赖倒转原则: 抽象应该依赖于细节,细节应该依赖于抽象(要针对接口编程,而不是实现编程)
接口隔离原则:客户端不应该依赖那些它不需要的接口
(当接口太大时,需要分割为细小接口,每种接口应承担相对独立的角色)
合成复用原则(组合/聚合复用原则):优先使用对象组合,而不是继承来完成复用
迪米特法则(最少知识法则,降低耦合度):尽量减少对象之间的交互,可以通过引入中间类来降低耦合度
设计模式概述
一套反复被使用、多数人知晓、经过分类编目的、代码设计经验的总结,
为了提高代码可重用性、理解性、可靠性
基本要素
模式名称
问题
解决方案
效果
分类
根据目的分类:
创建型(创建对象)
结构型(处理类或对象的组合)
行为型(大部分)(描述类或对象如何交互和怎样分配职责)
根据范围分类:
类模式:处理与子类之间的关系
对象模式(大部分):处理对象之间的关系
二、创建型模式
简单工厂模式(静态方法)
可以根据参数的不同返回不同的实例(客户端无需知道具体类名,只需知道参数即可)
被创建的实例通常有共同的父类
对象的创建与业务本身分离(降低耦合度)
工厂类的职责面对过重,扩展困难,违背开闭原则
适用于:
工厂类创建的对象比较少
只需要知道传入参数,对象如何创建不关心
工厂方法模式/工厂模式
简单工厂模式的进一步抽象与推广
工厂父类定义产品对象的公共接口
工厂子类生成具体的产品对象
将产品实例化操作延迟到子类(由子类决定实例化具体产品)
扩展时只需要增加工厂子类即可,符合开闭原则
但多个工厂增加了开销,增加系统抽象性与理解难度
适用于:
不知道所需要的类
通过子类来指定创建哪个对象
抽象工厂模式(对象创建型,Kit模式)
提供一系列相关或相互依赖的接口而无需指定具体类
产品登记结构:不同工厂生产的,同一产品
产品族:同一工厂生产的,位于不同等级结构/继承结构的产品
包含角色:抽象工厂、具体工厂、抽象产品、具体产品
隔离了具体类的生成
保证客户端始终只使用同一个产品族的对象
新增产品族很方便,符合开闭原则
适用于:
不应该依赖于产品如何被创建、组合和表达的细节
每次只使用其中一个产品族
产品等级结构稳定
建造者模式(使用频率不高)
对复杂对象的构建与其表示分离
一步一步创建一个复杂的对象,只通过指定复杂的对象类型与内容就可以构建,无需知道具体构造内部细节
包含角色:抽象建造者(Builder),具体建造者(ConcreteBuilder),指挥者(Director),产品角色(Product)
如果产品之间差异很大,不建议使用
如果产品内部变化复杂,可能需要很多具体建造者来实现,加大开销
适用于:
产品对象结构复杂
产品对象的属性相互依赖
对象的创建过程独立于创建该对象的类
隔离复杂对象的创建与使用
原型模式(克隆)
复制一个对象,克隆出多个与原型一样的对象
给出一个原型对象来指明要创建的类型,然后复制原型来创建同类对象
用户不需要知道创建细节
拥有角色:抽象原型类,具体原型类,客户类
Java.lang.Object提供Clone方法,被克隆的类要实现一个接口Cloneable,否则会抛出CloneNotSupportedException
浅克隆:只复制其本身与其包含的值类型的成员变量,引用类型的并未复制
深克隆:出了本身被复制以外,包含的所有成员变量都被复制
简化对象创建过程、扩展性好、简化创建结构,可以利用深克隆保存对象状态
适用于:
创建新对象成本较大
对象的状态变化很小
需要避免使用分层次的工厂模式
单例模式(一个类只有一个实例)
自行实例化并向整个系统提供该实例
Java中可以利用static
包含角色:单例
饿汉式单例类(无需考虑多线程,反应时间快,资源利用效率不高,加载时间长)
懒汉式单例类(双重检查锁定,延迟加载(要用到时在创建),性能较差)
提供对唯一实例的受控访问
节约系统资源,提高系统性能
允许多例类
扩展困难(缺少抽象层),职责过重
适用于:
只需要一个实例对象
只允许使用一个访问点
三、结构型模式
适配器模式(将接口转换为另一个客户需要的接口)
使不兼容的接口(方法,或方法的集合)可以一起工作
Target:目标抽象类
Adapter:适配器类(用来转化)
Adaptee:适配者类(被转化的)
类适配器
新增一个类Adapter 继承Adaptee与Target来完成,引用super.XXX()方法
对象适配器(使用更多,因为继承类适配器的同时继承两个父类在代码上不容易实现)
新增一个类Adapter 继承Target,关联Adaptee,调用Adaptee.XXX
适用情况
需要利用现有类完成需求,但目前已有需求不满足需要。
创建可以重复使用的类
桥接模式(抽象部分与实现部分分离,使之都可独立变化)
将多个维度的变化相互独立出来
将类的静态的继承关系变为动态的对象组合关系
Asbtraction:抽象类
RefinedAbstraction:扩充抽象类
Implementor:实现类接口
ConcreteImplementor:具体实现类
分离抽象接口
可以取代多层继承,不需要建立静态继承关系,减少了子类个数
提高系统可扩展性
会增加系统设计与理解难度
识别两个独立变化的维度困难
组合模式(树形结构,整体与部分的关系)
对容器与叶子进行递归组合,容器与叶子具有一致性
Component:抽象构件:
Leaf:叶子构件
Composite:容器构件
可以定义分层次的复杂对象
新增容器与叶子很方便
树形结构的面向对象实现
很难对构件的类型进行限制
透明组合模式
Component 声明了所有用于管理成员对象的方法(add,remove,getChild等),
客户端可以一致地对待所有对象,但不够安全
适用情况
树形结构/具有整体、部分的层次结构
装饰模式(动态地给对象增加额外职责,用关联替代继承)
再不改变对象原本功能上给对象增加额外的新行为,不需要引入新子类
但比继承更容易出错
引入装饰类,既可以调用原有类的方法,又可以增加新的方法
可以多次装饰
具体构建类与具体装饰类可以独立变化(类似桥接模式)
Component:抽象构件类
ConcreteComponent:具体构件类
Decorator:装饰类
ConcreteDecorator:具体装饰类
透明装饰模式(完全抽象)
可以对已经被装饰过的类进行再装饰,不可调用addedBehavior
半透明装饰模式(具体构件用抽象构件类型来定义)
不可再装饰,可调用addedBehavior
使用情况
动态透明的方式给类添加职责
不采用继承的方法来扩展或继承方法
外观模式/门面模式(用于客户类同时与多个业务类进行互动,对象)
为客户类提供统一入口(外观类),简化类与类之间的交互,降低耦合度。
子系统修改对其他子系统不影响,且内部变化不影响外观对象
但因为无法直接调用子系统,降低灵活性与可变性(外观类同时执行所有的子系统),且增加/减少子系统需要修改外观类
Facade:外观
SubSystem:子系统
享元模式/轻量级模式(实现对象多次重用,使用较少,结构)
避免系统出现大量相似或项目的对象,支持大量细粒度对象复用
FlyWeight:抽象享元类
ConcreteFlyWeight:具体享元类
UnsharedConcreteFlyWeight:非共享享元类
FlyWeightFactory:享元工厂类
内部状态:在享元内部,可以内部共享,不会随着环境而改变。
外部状态:在享元外部,不能共享,会随着环境改变而改变。
减少内存中对象的数量,节约资源提升性能。
但逻辑复杂化,读取外部状态使得运行时间变长。
代理模式(引入代理对象间接访问)
代理对象控制原对象,起到中介的作用,降低耦合度。
实现新的额外服务或隐藏客户不能看到的内容。
部分代理类型会使系统变慢,逻辑复杂化
Subject:抽象主题
Proxy:代理主题
RealSubject:真实主题
远程代理
虚拟代理
保护代理
缓冲代理
智能引用代理
四、行为型模式
职责链模式(有多个接受请求者,对象行为)
让业务沿着职责链(可以是单向链、树形结构)完成,降低耦合度
职责分配更灵活
新增请求处理者时无需修改原有代码,只需要重新排列链即可。
Handler:抽象处理者
ConcreteHandler:具体处理者
请求不一定会被处理,较长的职责链会影响执行时间,建链不当会死循环。
适用情况
多个对象同时处理一个请求
动态指定一组对象处理请求
命令模式(发送者请求封装在对象中,并调用处理方法)
将请求封装为一个命令对象,可以对命令进行请求排队 (命令队列) 、记录日志、撤销/恢复等。
发送者与接收者完全解耦,没有直接引用关系。
同一个请求发送者可以对应不同的接受者。
具体命令类可能过多
Invoker:发送者
Receiver:接收者
命令模式可以和组合模式相结合->宏命令:内部由多个子命令组成(类似组合模式结构)
迭代器模式(访问聚合对象中的元素而不暴露内部结构,对象行为)
将遍历数据的行为从聚合对象中分离,简化聚合对象。
因为有抽象层,因此新增与更聚合类与迭代器改都很方便。
JDK内置迭代器
支持以不同的方式遍历聚合对象
利用游标实现
Aggregate:抽象聚合类
ConcreteAggregate:具体聚合类
Iterator:抽象迭代器
ConcreteIterator:具体迭代器
观察者模式/从属模式/模型-视图模式/发布-订阅模式/源-监听器模式(一个对象的状态或行为变化将导致其他对象的状态也发生变化,即联动,对象行为)
定义观察目标(变化的对象)对观察者(跟着变化的)产生了一对多依赖关系,实现抽象耦合。
实现表示层与数据逻辑层的分离,支持广播通信。
产生循环依赖会崩溃
花费更多时间
无法知道内部如何变化,只知道变化了(变化过程不透明)
Subject:抽象观察目标
ConcreteSubject:具体观察目标
Observer:抽象观察者
ConcreteObserver:具体观察者
attach/detach方法:注册/注销观察者
notify方法:通知观察者
有时具体观察者中需要用到具体观察目标的属性(即产生关联或依赖),此时系统的扩展性将受到一定影响。
适用情况
需要在系统中创建触发链(a->b->c…)
状态模式(对象拥有多种状态,改变状态时会改变行为,对象行为型)
封装状态转换,对象的状态分离 到专门的 状态类中
但会增加系统中类的个数,使用不当时会使代码混乱
适用情况
对象行为依赖于状态
策略模式(根据情况选择最合适的实现途径)
采用策略类封装算法,并且可以相互替换、复用。
可以替换继承关系,避免多重if语句
客户必须知道所有策略类,且无法同时使用多个策略类(只有一个)
使用情况
需要动态地从几种算法中选择一种
避免难以维护的多重if
提高安全性与保密性
模板方法模式(定义算法框架,将步骤延迟到子类中,类行为)
基于继承的代码复用技术
实现步骤封装在基本方法中
在父类定义模板方法来定义基本方法的执行次序。
子类实现某些步骤,从而使相同算法有不同执行结果
templateMethod:模板方法
primitiveOperation:具体方法
子类的实现不会改变算法的执行次序
公共行为在父类中
可实现反向结构,通过子类覆盖父类方法来决定钩子方法是否要执行
会导致类的个数增加,更加复杂。
使用情况
各子类的公共行为被提取到公共父类中
子类决定父类的方法是否执行
访问者模式(以不同的方式操作复杂结构)
对象中有不同类型的信息,操作方式不唯一,需要提供多种处理方式
增加/删除新的处理方式很方便
类的职责清晰
可以在不修改层次结构的情况下,定义作用于层次结构的操作
破坏对象封装性,新增Element很难
Visitor:抽象访问者
ConcreteVisitor:具体访问者
Element:抽象元素
ConcreteElement:具体元素
ObjectStructure:对象结构
使用情况
结构中对应多个对象,希望实施一些依赖具体型的操作。
对象对应的类很少改变
对象会进行许多且不相关的操作,且需要避免操作“污染”类,也不希望在新增/删除时影响这些类