设计模式
设计模式
- 依赖和关联(简单理解):当A使用B作为变量或者方法参数,叫依赖关系。当A使用B作为类属性,则叫关联关系,关联关系是一种强依赖关系。
- 多态的向上转型:父类类型 父类引用名 = new 子类类型();
- 编译阶段看左边的父类型,所以不能调用子类特有的成员,否则编译不通过
- 运行阶段看右边的子类型,调用方法从子类开始查找,一般调用子类重写的方法,属性无重写
1. 单例模式
理解:单例模式确保某一个类只有一个实例,自行实例化,给系统提供全局访问方法
例子:任务管理器、身份证、打印池
优缺点
- 缺点:违反“单一职责原则”
类图:见书
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Singleton
{
private static Singleton instance = null; // 静态私有成员变量
// 私有构造函数
private Singleton(){
}
// 静态公有工厂方法,返回唯一实例
public static Singleton getInstance(){
if(instance == null)
instance = new Singleton();
return instance;
}
}测试:
1
2
3
4
5
6
7public class Singleton{
public static void main(String a[]){
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
2. 迭代器模式
- 理解:聚合对象有两个功能:一是存储内部数据,二是遍历内部数据。把遍历行为提取成为迭代器。
- 大概率只考察类图:抽象和具体迭代器 and 抽象和具体聚合类
- 例子:迭代器——电视遥控器 聚合类————电视机
- 代码理解:
- 抽象迭代器只有抽象迭代方法声明,抽象聚合类只有抽象创建迭代器方法声明
- 具体聚合类:一是有数据,二是实现创建具体迭代器(返回一个具体迭代器对象),三是包含具体迭代器的类(即内部类的方式,也可以用另一种方式,单独写一个具体迭代器类,初始化需要具体聚合类参数)
3. 策略模式
理解:将一系列算法封装起来,由环境类(使用算法的角色)选择使用哪种算法
例子:环境类(数组处理类)、抽象策略类、具体策略类(冒泡插入选择排序)
代码理解:
- 环境类有set方法,用于设置具体策略类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class Context{ // 环境类
private Strategy strategy;
public void setStrategy(Strategy strategy){
this.strategy = strategy;
}
private void contextAlgorithm(...){
strategy.algorithm(...);
}
}
public interface Strategy{ // 抽象策略类 or 策略类接口
public void algotithm(...);
}
public class StrategyA implements Strategy{ // 具体策略类A
public void algotithm(...){
...
};
}
public class StrategyB implements Strategy{ // 具体策略类B
public void algotithm(...){
...
};
}测试
1
2
3
4
5
6
7
8public class Client{
public static void main(){
Context c = new Context();
StrategyA sa = new StrategyA();
c.setStrategy(sa);
c.contextAlgorithm(...);
}
}
4. 工厂模式
三个模式之间的关系:
- 当抽象工厂模式每一个具体工厂类只创造一个产品对象,抽象工厂退化为工厂方法模式
- 当工厂方法模式抽象工厂与具体工厂合并,只有一个统一的工厂来创建产品对象,工厂方法模式退化为简单工厂模式
关于抽象工厂模式是否符合开闭原则
- 如果增加产品族(由一个工厂生产的所有商品),只需要增加具体工厂,符合OCP
- 如果增加产品等级结构(同一种商品),要修改所有工厂类,不符合OCP
关于工厂模式与策略模式的比较:工厂模式用于创建对象,策略模式用于选择各种方法
工厂方法UML图:
5. 观察者模式
很好理解
例子:主题类(猫),观察者(老鼠、狗)猫叫后老鼠和狗都有动作
类图:抽象主题(观察者数组、增加、删除观察者)、抽象观察者、具体主题(提醒观察者)、具体观察者
代码示例:
1 |
|
6. 建造者模式
- 和工厂模式很像,也是对象创建型模式,创建复杂的对象,关注各个配件的创建,有一个指挥者
7. 原型模式
- 通过复制(clone)原型来创建对象
8. 适配器模式
让目标类可以做适配类的行为,类适配要用接口,对象适配只用继承
分为类适配器和对象适配器
- 类适配器实现目标类,继承适配类的接口(比如让robot可以学dog叫,因为狗叫是dog已实现的方法,所以继承dog,实现robot)(抽象和实现的区别:抽象可以选择父类方法调用,实现必须实现接口所有方法)
- 对象适配器继承目标类,关联适配类(把适配类当作变量)
使用时候,用目标类作为父类创建适配器
类图:
9. 桥接模式
一个类有两个独立变化的维度,把两个维度分离开,独立扩展
抽象化:把类的共同性质抽取出来形成抽象类,比如不同颜色的毛笔都是毛笔
实现类:另一个维度的实现部分,比如毛笔的颜色
抽象类与实现类有聚合关系(桥)
例子:不同操作系统上播放多种格式的视频文件、描述不同制造商以及制造的电器种类
类图
10. 组合模式
想到组合模式就应该想到树形结构图,对叶子和容器的使用要有一致性
用抽象构件作为叶子和容器的抽象,容器和构件建立组合关系,容器有构件的数据可以遍历
例子:水果盘里有水果和水果盘;文件夹浏览和文件浏览方式;
类图
11. 装饰模式
对原有对象的功能进行扩展
对类功能进行复用时应该多用关联关系,少用继承关系
UML图和组合模式很像,但原理不同
抽象构件有一个默认具体构件类,比如煎饼果子默认加蛋
理解:咖啡加很多调料,如果用继承关系,把各种调料方式的咖啡都建立一个子类,会有类爆炸。所以使用装饰模式,建立各种调料的类,用调料调用咖啡进行装饰。
例子:变形金刚;
类图(抽象装饰类和具体装饰类的初始化有说法)
12. 外观模式
对外提供一个统一的接口用来访问子系统
对客户屏蔽子系统组件,降低客户类与子系统类的耦合度
eg:网站首页有各个子栏目;电源总开关控制很多子开关
UML图很简单,外观类关联很多子系统类
违反OCP,增加子系统会修改外观类代码,抽象外观模式符合OCP
体现单一职责,体现迪米特
13. 代理模式
代理对象控制对对象的访问
很简单:代理对象有对象的变量,自己有控制等级变量,根据控制等级,调用对象的方法。因为要满足OCP所以继承一个抽象对象
客户端调用代理对象,完成对对象的代理访问
14. 命令模式
将一个请求封装成一个对象,发送请求的对象只需要知道如何发送请求,不必知道如何完成请求
分为请求发送控制者和请求接收者,抽象请求和具体请求。发送者有很多请求对象,请求对象有发送接收者成员变量。发送者调用请求,请求调用接收者的方法
客户端建立请求控制对象,建立请求,初始化请求控制对象
15. 中介者模式
中介者模式可以使对象之间的关系数量急剧减少,变成以中介者为中心的星状结构(私聊变群聊)
分为抽象中介和具体中介、抽象同事和具体同事,具体中介有同事数组作为成员变量,抽象同事有抽象中介作为成员变量,用来调用中介的方法进行通信
考代码的话稍微有点复杂,画类图很简单
16. 备忘录模式
17. 状态模式
对象在不同状态下的行为不同,且可以自动转换状态
例子:论坛用户等级、银行账户状态、两个开关同时开关
优缺点
- 缺点:对开闭原则支持不太好,可以切换状态的状态模式,增加状态需要修改负责状态转换的代码
类图包括环境类(拥有状态的对象)、抽象状态类(封装与状态相关的行为)、具体状态类