设计模式summer
yuiyake 6/26/2021
# 设计原则
- 单一指责原则
- 一个类只有一个引起它变化的原因,应该只有一个指责。
- 开闭原则
- 对扩展开放,对修改关闭。尽量避免修改源代码的行为。
- 里式替换原则
- 任何基类可以出现的地方,子类一定可以出现。lsp是继承复用的基石, 衍生类可以替换掉基类或者在基类上增加新行为
- 依赖倒转原则
- 依赖于抽象,不要依赖于具体。关键是抽象化,实现解耦,降低耦合度。
- 接口隔离原则
- 用多个隔离的接口,比用单个接口好。
- 合成复用原则
- 要尽量使用组合/聚合关系,少用继承。
- 迪米特法则
- 一个实体应当尽量少的与其他实体发生相互作用。
# 创建型模式
# 单例模式
- 懒汉式(调用才实例)
- 步骤
- 创建单例类,声明自己静态私有对象,创建私有构造方法和以自己为实例返回值的静态公有方法,工厂方法,里面是被动创建(if自己==null, 则create)
- 客户端 将但李磊实例化,调用
- 线程不安全,延迟初始化
- 代码(这是改进过的线程安全版)
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
1
2
3
4
5
6
7
8
9
10 - 饿汉式(声明即实例)
- 步骤
- 创建单例类,声明并创建自己的静态私有对象和私有构造方法,还有自己类型返回自己的静态公有方法,静态工厂方法
- 客户端一样
- 代码
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
1
2
3
4
5
6
7 - 优缺点
- 优 节约系统资源,允许可变数目的实例,提供了对唯一实例的受控访问
- 缺 单例模式扩展会十分困难,违背单依职责原则
# 工厂模式
- 抽象工厂
动机
- 系统中产品有多于一个的产品族,但只消费其中一种。解决接口选择的问题。
步骤
- 包含这些角色
AbstractFactory:抽象工厂 ConcreteFactory:具体工厂 AbstractProduct:抽象产品 ConcreteProduct:具体产品
1
2
3
4- 为产品创建接口,并创建实现接口的实体类。
- 为产品对象创建抽象类
- 创建扩展抽象类的实体类,基于给定的信息生成实体类对象
- 创建工厂创造器类,通过传递产品信息获取工厂
- client
// 抽象工厂
public abstract class AbstractFactory{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
// 具体工厂
public class ConcreteFactory1 extends AbstractFactory{
public abstractProductA createProductA(){
return new ConcreteProductA1();
}
public abstractProductA createProductA(){
return new ConcreteProductA1();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 优点
- 隔离了具体类的生成,使得客户端并不需要知道什么被创建
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
- 增加新的产品族很方便,无须修改已有系统,符合开闭原则
- 缺点
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则
# 原型模式
- 动机
- 通过给出一个原型对象指明所要创建的对象的类型,然后通过复制这个原型对象的办法创建出更多同类型的对象。
- 步骤
- 包含这些角色
Prototype(抽象原型类)
ConcretePrototype(具体原型类)
Client(客户端)
1
2
3
2
3
// 浅克隆
public clas PrototypeDemo implements Cloneable {
...
public Object clone() {
Object obj = null;
try{
object = super.clone();
} catch(CloneNotSupportException exception) {
System.err.printlm("Not support cloneable");
}
return obj;
}
}
// 客户端调用
PrototypeDemo obj1 = new PrototypeDemo();
PrototypeDemo obj2 = obj1.clone();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
浅克隆
- 创建具体原型类继承Cloneable(自带),调用Object的clone()方法返回一个克隆的原型对象
- 客户端
深克隆
- 创建具体原型类,这个深克隆后面自己看代码吧orz他是没有用clone()方法的,用流来实现
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一 定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
# 建造者模式
- 动机
- 将一个复杂对象的构建与它的表示分离,使同样的构建过程可以构建不同的表示。
- 步骤
- 包含这些角色
Builder(抽象建造者) ConcreteBuilder(具体建造者) Product(产品角色) Director(指挥者)
1
2
3
4- 创建产品类,定义各产品对象及getter,setter
- 创建抽象建造者类,定义抽象方法和定义产品类的对象getChan返回产品对象
- 创建具体建造者类A,B...继承抽象,改写方法
- 创建指挥者类,定义抽象建造者类型对象,再声明一个方法调用对象的部分组装方法和工厂方法。
public class Protect { private String name; private String sex; Setter&Getter... } public abstract class Builder { protected Product product = new Product(); public abstract void buildName(); public abstract void buildSex(); public Product getResult() { return product; } } public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public void setBuilder(Builder builder) { this.builder = builder; } public Product construct(){ builder.buildName; builder.buildSex; return builder.getBuildt; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
- 缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
# 结构型模式
# 适配器模式
- 动机
- 现有接口需要转化为客户类期望的接口,保证复用现有类。(通俗解释就是我的本子需要充电,但是要求的电压和插座电压不一致, 这时候就要一个电源适配器。)
- 类适配器
- 对象适配器
- 包含以下主要代码
Target(目标抽象类) Adapter(适配器类) Adaptee(适配者类) Client(客户端)
1
2
3
4// 类适配器 public class Adapter extends Adaptee implements Target { public void request(){ super.specificRequest(); } } // 对象适配器 public class Adapter extends Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public void request() { adaptee.specificRequest(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 优缺点
- 优点
- 增加了类的透明性和复用性
- 灵活性和扩展性都非常好
- 适配器与目标解耦
- 缺点
- 对象适配器
- 与类适配器模式相比,要想置换适配者类的方法就不容易。
- 类适配器
- 对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类, 其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
- 对象适配器
- 优点
# 桥接模式
- 动机
- 将抽象部分与实现部分分离,使它们可以独立变化(有点aop内味了)。
- 步骤
- 包含这些角色
Abstraction(抽象类) RefinedAbstraction(扩充抽象类) Implementor(实现类接口) ConcreteImplementor(具体实现类)
1
2
3
4- 创建产品类,定义各产品对象及getter,setter
- 创建抽象建造者类,定义抽象方法和定义产品类的对象getChan返回产品对象
- 创建具体建造者类A,B...继承抽象,改写方法
- 创建指挥者类,定义抽象建造者类型对象,再声明一个方法调用对象的部分组装方法和工厂方法。
// 抽象化
public interface Implementor{
public void operationImpl();
}
// 实现化
public abstract class Abstraction {
protected Implementor impl;
public void setImp(Implementor impl) {
this.impl = impl;
}
public abstract void operation();
}
// 脱耦
public class RefineAbstraction extends Abstraction{
publid void operation() {
...
impl.operationImpl();
...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。
- 缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
# 组合模式
动机
- 通过组合多个对象形成树形结构以表示整体-部分的结构,对叶子对象和容器对象的使用具有一致性。
包含以下
Component(抽象构件)
Leaf(叶子构件)
Composite(容器构件)
Client
1
2
3
4
2
3
4
- 透明组合模式
- 安全组合模式
- 透明和安全的区别在透明是所有方法都直接声明在抽象构件里的,但是安全是只声明全局方法,其他的add啊remove啊这些都是在容器构件里实现
// 这是透明组合模式的抽象构件,全部方法都声明在内,容器或叶子构件都要继承但不一定用得上
public abstract class Component{
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract Component getChild(int i);
public abstract void operation();
}
// 叶子组件
public class Leaf extends Component {
public void add(Component c){// 异常处理or错误提示}
public abstract void remove(Component c){// 异常处理or错误提示}
public abstract Component getChild(int i){// 异常处理or错误提示 return null;}
public abstract void operation(){
// 具体实现代码
}
}
// 容器构件,主要是operation方法把容器里的叶子一个个拎出来执行一遍
public class Composite extends Component {
private ArrayList list = new ArrayList();
public void add(Component c) {
list.add(c);
}
public abstract void remove(Component c){
list.remove(c);
}
public abstract Component getChild(int i){
return (Component)list.get(i);
}
public abstract void operation(){
for(Object obj:list){
((Component)obj).operation();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- 优点: 1、高层模块调用简单。 2、节点自由增加。
- 缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
# 装饰模式
动机
- 动态给对象增加一些额外职责。
包含以下
Component(抽象构件)
ConcreteComponent(具体构件)
Decorator(抽象装饰类)
ConcreteDecorator(具体装饰类)
1
2
3
4
2
3
4
核心代码
// 抽象装饰类,里面并没有具体的实施代码,只是调用component对象的operation方法,提供一个统一的接口给子类完成。
public class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation(){
component.operation();
}
}
// 具体装饰类,继承抽象的方法同时也可以自己新增方法
public class ConcreteDecorator extends Dector {
public ConcreteDecorator(Component component) {
super(component);
}
public void operation() {
super.operation();
addedBehavior();
}
public void addedBehavior() {
// 新增方法
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
- 缺点:多层装饰比较复杂。
# 外观模式
动机
- 为复杂子系统提供一个统一入口。
包含以下
Facade(外观角色)
SubSystem(子系统角色)
1
2
2
核心代码
// 外观类更像是一个控制开关,负责调用各个子系统里的方法
public class Facade {
private SubSystemA obj1 = new SubStstemA();
private SubSystemB obj2 = new SubStstemB();
public void method() {
obj1.method();
obj2.method();
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。
- 缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
# 享元模式
动机
- 通过运用共享技术有效地支持大量细粒度对象的复用。
包含以下
Flyweight(抽象享元类)
ConcreteFlyweight(具体享元类)
UnsharedConcreteFlyweight(非共享具体享元类)
FlyweightFactory(享元工厂类)
1
2
3
4
2
3
4
核心代码
// 享元工厂
public class FlyweightFactory {
private HashMap flyweights = new HashMap();
public Flyweight getFlyweight(String key) {
if(flyweights.containsKey(key))
return (Flyweight)flyweights.get(key);
else {
Flyweight fw = new ConcreteFlyweight();
flyweights.put(key,fw);
return fw;
}
}
}
// 享元类
public class Flyweight {
//内部状态作为成员属性,同一个享元对象其内部状态一致
private String intrinsicState;
public Flyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
// 3外部状态在使用时由外部状态设置,不保存在享元对象中,同一个对象每次调用都可以传入不同的外部状态
public void operation(String extrinsicState) {
//....省略具体代码
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 优点:大大减少对象的创建,降低系统的内存,使效率提高。
- 缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
# 代理模式
动机
- 给扣一个对象一共一个代理,并由代理对象控制对原对象的引用。
包含以下
Subject(抽象主题角色)
Proxy(代理主题角色)
RealSubject(真实主题角色)
1
2
3
2
3
核心代码
// 代理类就负责接收,执行并传递结果
public class Proxy implements Subject {
private RealSubject rs = new RealSubject();
public void preRequest(){...}
public void request() {
preRequest();
rs.request();
postRequest();
}
public void postRequest(){...}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 优点: 1、职责清晰。 2、高扩展性。 3、智能化。
- 缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
# 行为型模式
# 观察者模式
动机
- 定义了对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
包含以下
Subject(目标/被观察对象)
ConcreteSubject(具体目标)
Observer(观察者)
ConcreteObserver(具体观察者)
1
2
3
4
2
3
4
核心代码
// 具体目标,声明三个方法,期中attach和remove是被观察对象的集合,用来添加&取出对象,notify是通知
public class ConcreteSubject extends Subject {
public void attach(Observer observer) {
observers.add(observer);
}
public void remove(Observer observer) {
observers.remove(observer);
}
public void notify() {
for(Object obs:observers) {
((Observer)obs).update();
}
}
}
// 抽象观察者角色一般定义为一个接口,为不同观察者的更新行为定义相同的借口,其方法在子类实现。
public interface Observer{
public void update();
}
// 实现具体方法
public class ConcreteObserver implements Observer {
public void update(){//具体代码}
}
// 这是客户端调用的代码段
Subject sb = new ConcreteSubject();
Observer ob = new ConcreteObserver();
sb.attach(ob);
sb.notify();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
- 缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果 在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没 有相应的机制让观 察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
# 状态模式
动机
- 允许一个对象在其内部状态改变时改变他的行为。
包含以下
Context(环境类)
State(抽象状态类)
ConcreteState(具体状态类)
1
2
3
2
3
核心代码
// 这里是用代码段表示意思,具体会很复杂看例子吧orz
if(预定房间) {
预定操作;
context.setState(new 已预定状态类());
} else if (入住房间) {
入住操作;
context.setState(new 已入住状态类());
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
- 缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循 环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发 生变化的,而仅仅只是知道观察目标发生了变化。
# 策略模式
动机
- 定义一系列算法,并将每个算法封装在一个类中,让它们可以相互替换,策略模式让算法独立于使用它的客户而变化。
包含以下
Context(环境类)
Strategy(抽象策略类)
ConcreteStrategy(具体策略类)
1
2
3
2
3
核心代码
// 抽象策略类
public abstract class AbstractStrategy {
public abstract void algorithm();
}
// 具体策略类
public class ConcreteStrategyA extends AbstractStrategy {
public void algorithm(){
//算法A代码
}
}
// 环境类,建立与抽象策略类之间的关联关系
public class Context {
private AbstractStrategy strategy;
public void setStrategy(AbstractStrategy strategy) {
this.strategy = strategy;
}
public void algorithm() {
strategy.algorithm();
}
}
// 客户端片段
Context c = new Context();
AbstractStrategy strategy;
strategy = new ConcreteStrategyA();
c.setStrategy(strategy);
c.algorithm();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- 优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
- 缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
# 解释器模式
动机
- 描述如何为语言定义一个问法,如何在该语言中表示一个句子,以及如何解释这些句子。
包含以下
AbstractException(抽象表达式)
TerminalException(终结符表达式)
NonterminalException(非终结符表达式)
Context(环境类)
Client
1
2
3
4
5
2
3
4
5
核心代码
//呃代码有点复杂自己去看吧这个不好总结orz
1
- 优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。
- 缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。
# 模板方法模式
动机
- 定义一个操作中算法的骨架,而将一些步骤延迟到子类中。
包含以下
AbstractClass(抽象类)
ConcreteClass(具体子类)
1
2
2
核心代码
public abstract class AbstractClass{
public void templateMethod() {
primitiveOperation1();
primitiveOperation2();
primitiveOperation3();
}
public void primitiveOperation1(){} //具体方法
public void primitiveOperation2(); //抽象方法
public void primitiveOperation3(){} //钩子方法
}
public class ConcreteClass extends AbstractClass {
public void primitiveOperation2(){
//实现代码
}
public void primitiveOperation3(){
实现代码
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
- 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
# 职责链模式
动机
- 避免请求发送者与接受者耦合在一起,让多个对象都有可能接收到请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
包含以下
Handler(抽象处理者)
ConcreteHandler(具体处理者)
Client
1
2
3
2
3
核心代码
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(String request);
}
public class ConcreteHandler extends Handler{
public void handleRequest(String request){
if(满足条件){//处理请求}
else{this.successor.handleRequest(request)} // 转发请求
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。 通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
- 缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容 易观察运行时的特征,有碍于除错。
# 命令模式
动机
- 将一个请求封装为一个对象,从而使得请求调用者和请求接收者解耦。
包含以下
Command(抽象命令类)
ConcreteCommand(具体命令类)
Invoker(调用者)
Receiver(接受者)
Client(客户类)
1
2
3
4
5
2
3
4
5
核心代码
public abstract class Command{
public abstract void execute();
}
public class Invoker{
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand //自己写了这个
// 用于调用命令类方法
public void call() {
command.execute();
}
}
public void Receiver{
public void action() {具体}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
- 缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
# 迭代器模式
动机
- 提供了一种方法来访问聚合对象,而不用暴露这个对象的内部表示。
包含以下
Iterator(抽象迭代器)
ConcreteIterator(具体迭代器)
Aggregate(抽象聚合类)
ConcreteAggregate(具体聚合类)
1
2
3
4
2
3
4
核心代码
// 迭代器接口,定义四个方法用于访问第一个元素,下一个元素,判断是否为最后一个元素,获取当前元素
public interface MyIterator {
void first();
void next();
boolean isLast();
Object currentItem();
}
// 定义聚合接口
public interface MyCollection {
MyIterator createIterator();
}
// 具体迭代器作为聚合类的内部类,迭代器可以直接访问聚合类中的数据
public class new Collection implements MyCollection {
private Object[] obj = {"dog","cat","pig"};
public MyIterator createIterator() {
return new NewIterator();
}
private class NewIterator implements MyIterator {
private int currentIndex= 0;
public void first(){
currentIndex = 0;
}
public void next)_ {
if(currentIndex<obj.length){
currentIndex++;
}
}
public bollean isLast() {
return currentIndex == obj.length;
}
public Object currentItem() {
return obj[currentIndex];
}
}
}
// 客户端
public class Client{
public static void process(MyCollection collection) {
MtIterator i = collection.createIterator();
while(!i.isLast()){
syso(i.currentItem().toString());
i.next();
}
}
main{
MyCollection collection = new NewCollection();
process(collection);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
- 优点: 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式 中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
- 缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程 度上增加了系统的复杂性。
# 中介者模式
动机
- 通过一个中介对象来封装一系列的对象交互,使各对象不需要显示地相互调用,从而使耦合松散,且可以独立地改变它们之间的交互。
包含以下
Mediator(抽象中介者)
ConcreteMediator(具体中介者)
Colleague(抽象同事)
ConcreteColleague(具体同事)
1
2
3
4
2
3
4
核心代码
public abstract class Mediator{
protected ArrayList colleagues;
public void register(Colleague colleague) {
colleagues.add(colleague);
}
public abstract void operation();
}
// 在具体中介者类里调用同事类的方法,调用时可以增加一些自己的业务代码对调用进行控制
public class ConcreteMediator extends Mediator {
public void operation(){
...
((Colleague)(colleagues.get(0))).method1();
...
}
}
// 抽象同事类维持了对抽象中介者的引用
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator){
this.mediator = mediator;
}
public abstract void method1();
public abstract void method2();
}
// method2是依赖方法,即调用在中介者中定义的方法,依赖中介者完成相应行为。
public class ConcreteColleague extends Colleague{
public ConcreteColleague(Mediator mediator) {
super(mediator);
}
public void method1(){..}
public void method2(){
mediator.operation1();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- 优点: 1、降低了类的复杂度,将一对多转化成了一对一。 2、各个类之间的解耦。 3、符合迪米特原则。
- 缺点:中介者会庞大,变得复杂难以维护。
# 备忘录模式
动机
- 在不破坏封装的情况下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象皆得到通知并被自动更新。
包含以下
Originator(原发器)
Memento(备忘录)
Caretaker(负责人)
1
2
3
2
3
核心代码
public class Originator {
private String state;
public Originator() {}
// 创建一个备忘录对象
public Memento createMemento() {
return new Memento(this);
}
public void restoreMemento(Memento m){
state = m.state;
}
public void setState(String state) {
this.state = state;
}
public String getState(){
return this.state;
}
}
// 备忘录类,为原生类提供状态
class Memento{
private String state;
public Memento(Originator o) {
state = o.state;
}
public void setState(String state) {
this.state = state;
}
public String getState(){
return this.state;
}
}
// 负责人类的作用仅仅用于存储备忘录对象。
public class Caretaker{
pricate Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento m){
this.m = memento;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
- 优点: 1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。 2、实现了信息的封装,使得用户不需要关心状态的保存细节。
- 缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。