前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 23种设计模式全归纳 | 已打包请带走

Java 23种设计模式全归纳 | 已打包请带走

原创
作者头像
Jingbin
修改2020-02-13 14:51:57
6400
修改2020-02-13 14:51:57
举报
文章被收录于专栏:Android 技术栈Android 技术栈

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

设计模式分为三种类型,共23种:

GitHub:youlookwhat/DesignPattern

参照Hongyang、菜鸟教程等处文章所写。如有错误欢迎指正,如有侵权,请联系我删除。


Blog Catalogue:

Source Code

Observer Factory Singleton Strategy Adapter Command Decorator Facade Template Method State Builder Prototype Flyweight Proxy Bridge Composite Iterator Mediator Memento Chain of Responsibility Visitor

Project Picture

ds2.png
ds2.png

Pattern Analysis

1. 观察者模式

定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。
  • 专题接口:Subject.java ;
代码语言:txt
复制
```java
代码语言:txt
复制
/**
代码语言:txt
复制
 * 注册一个观察者
 */
public void registerObserver(Observer observer);
代码语言:txt
复制
/**
代码语言:txt
复制
 * 移除一个观察者
 */
public void removeObserver(Observer observer);
代码语言:txt
复制
/**
代码语言:txt
复制
 * 通知所有观察者
 */
public void notifyObservers();
```
代码语言:txt
复制
```java
代码语言:txt
复制
@Override
代码语言:txt
复制
public void registerObserver(Observer observer) {
代码语言:txt
复制
    observers.add(observer);
代码语言:txt
复制
}
代码语言:txt
复制
@Override
代码语言:txt
复制
public void removeObserver(Observer observer) {
代码语言:txt
复制
    int index = observers.indexOf(observer);
代码语言:txt
复制
    if (index >= 0) {
代码语言:txt
复制
        observers.remove(index);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
@Override
代码语言:txt
复制
public void notifyObservers() {
代码语言:txt
复制
    for (Observer observer : observers) {
代码语言:txt
复制
        observer.update(msg);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
/**
代码语言:txt
复制
 * 主题更新信息
 */
public void setMsg(String msg) {
    this.msg = msg;
    notifyObservers();
}
```
代码语言:txt
复制
```java
代码语言:txt
复制
 public ObserverUser1(Subject subject) {
代码语言:txt
复制
    subject.registerObserver(this);
代码语言:txt
复制
}
代码语言:txt
复制
@Override
代码语言:txt
复制
public void update(String msg) {
代码语言:txt
复制
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
// 创建服务号
代码语言:txt
复制
objectFor3D = new ObjectFor3D();
代码语言:txt
复制
// 创建两个订阅者
代码语言:txt
复制
observerUser1 = new ObserverUser1(objectFor3D);
代码语言:txt
复制
observerUser2 = new ObserverUser2(objectFor3D);
代码语言:txt
复制
// 两个观察者,发送两条信息
代码语言:txt
复制
objectFor3D.setMsg("201610121 的3D号为:127");
代码语言:txt
复制
objectFor3D.setMsg("20161022 的3D号为:000");
代码语言:txt
复制
```

2. 工厂模式

简单列一下这个模式的家族:

  • 1、静态工厂模式
代码语言:txt
复制
- 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍) - 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 - 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
代码语言:txt
复制
```java
代码语言:txt
复制
public RoujiaMo creatRoujiaMo(String type) {
代码语言:txt
复制
    RoujiaMo roujiaMo = null;
代码语言:txt
复制
    switch (type) {
代码语言:txt
复制
        case "Suan":
代码语言:txt
复制
            roujiaMo = new ZSuanRoujiaMo();
代码语言:txt
复制
            break;
代码语言:txt
复制
        case "La":
代码语言:txt
复制
            roujiaMo = new ZLaRoujiaMo();
代码语言:txt
复制
            break;
代码语言:txt
复制
        case "Tian":
代码语言:txt
复制
            roujiaMo = new ZTianRoujiaMo();
代码语言:txt
复制
            break;
代码语言:txt
复制
        default:// 默认为酸肉夹馍
代码语言:txt
复制
            roujiaMo = new ZSuanRoujiaMo();
代码语言:txt
复制
            break;
代码语言:txt
复制
    }
代码语言:txt
复制
    return roujiaMo;
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、工厂方法模式(开分店) - 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。 - 对比定义: - 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type); - 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java
代码语言:txt
复制
 ```java

public abstract RoujiaMo sellRoujiaMo(String type);

代码语言:txt
复制
 ```
  • 具体实现抽象方法:XianRoujiaMoStore.java
  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java
  • 4、抽象工厂模式(使用官方提供的原料) - 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。 - 对比定义: - 1、提供一个接口:public interface RouJiaMoYLFactroy - 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。 - 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java - 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java - 准备时,使用官方的原料:RoujiaMo.java
代码语言:txt
复制
 ```java
代码语言:txt
复制
 /**
代码语言:txt
复制
 * 准备工作
 */
public void prepare(RoujiaMoYLFactory roujiaMoYLFactory) {
    	Meet meet = roujiaMoYLFactory.creatMeet();
    	YuanLiao yuanLiao = roujiaMoYLFactory.creatYuanLiao();
    	Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
}
 ```

3. 单例设计模式

单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例

  • 定义:只需要三步就可以保证对象的唯一性
    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:
    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式可用:SingletonEHan.java
  • 含懒汉式双重校验锁 推荐用:SingletonLanHan.java
代码语言:txt
复制
代码语言:txt
复制
 private SingletonLanHan() {}
代码语言:txt
复制
 private static SingletonLanHan singletonLanHanFour;
代码语言:txt
复制
 public static SingletonLanHan getSingletonLanHanFour() {
代码语言:txt
复制
	    if (singletonLanHanFour == null) {
代码语言:txt
复制
		synchronized (SingletonLanHan.class) {
代码语言:txt
复制
		    if (singletonLanHanFour == null) {
代码语言:txt
复制
			singletonLanHanFour = new SingletonLanHan();
代码语言:txt
复制
		    }
代码语言:txt
复制
		}
代码语言:txt
复制
	    }
代码语言:txt
复制
	    return singletonLanHanFour;
代码语言:txt
复制
}
代码语言:txt
复制

4. 策略模式

策略模式:定义了算法族,分别封装起来,让它们之间可相互替换,此模式让算法的变化独立于使用算法的客户。

  • 以创建游戏角色为例子: - 最初的游戏角色的父类:Role.java - 发现有重复代码后,重构后的父类:Role.java
  • 总结: - 1、封装变化(把可能变化的代码封装起来) - 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法) - 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
代码语言:txt
复制

RoleA roleA = new RoleA("---A");

roleA.setiDisplayBehavior(new DisplayYZ())

代码语言:txt
复制
   .setiAttackBehavior(new AttackXL())
代码语言:txt
复制
   .setiDefendBehavior(new DefendTMS())
代码语言:txt
复制
   .setiRunBehavior(new RunJCTQ());

roleA.display();// 样子

roleA.attack();// 攻击

roleA.run();// 逃跑

roleA.defend();// 防御

代码语言:txt
复制

5. 适配器模式

定义:将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。这个定义还好,说适配器的功能就是把一个接口转成另一个接口。

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)
  • 一部手机: Mobile.java
  • 手机依赖一个提供5V电压的接口: V5Power.java
  • 我们拥有的是220V家用交流电: V220Power.java
  • 适配器,完成220V转5V的作用V5PowerAdapter.java
  • 最后测试:给手机冲个电:
代码语言:txt
复制
```java
代码语言:txt
复制
Mobile mobile = new Mobile();

V5Power v5Power = new V5PowerAdapter(new V200Power());

mobile.inputPower(v5Power);

代码语言:txt
复制
```

6. 命令模式

定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(简化: 将请求封装成对象,将动作请求者和动作执行者解耦。)

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类: - 统一的命令接口:Command.java - 家电实现该接口:DoorOpenCommand.java
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
代码语言:txt
复制

QuickCommand quickCloseCommand = new QuickCommand(new Command[]{new LightOffCommand(light), new ComputerOffCommand(computer), new DoorCloseCommand(door)});

controlPanel.setCommands(6, quickOpenCommand);

controlPanel.keyPressed(6);

代码语言:txt
复制
代码语言:txt
复制

controlPanel.setCommands(0, new DoorOpenCommand(door));// 开门

controlPanel.keyPressed(0);

代码语言:txt
复制

7. 装饰者模式

装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。
  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:
  • 1、装备的超类:IEquip.java
  • 2、各个装备的实现类:
  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java
  • 4、装饰品的实现类:
  • 5、最后测试:计算攻击力和查看描述:
代码语言:txt
复制
```java
代码语言:txt
复制
Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
代码语言:txt
复制
IEquip iEquip = new RedGemDecotator(new RedGemDecotator(new BlueGemDecotator(new ShoeEquip())));
代码语言:txt
复制
Log.e("---", "攻击力:" + iEquip.caculateAttack());
代码语言:txt
复制
Log.e("---", "描述语:" + iEquip.description());
代码语言:txt
复制
```

8. 外观模式

定义:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。其实就是为了方便客户的使用,把一群操作,封装成一个方法。

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。
  • 每个设备类的开关等操作:
  • eg: 爆米花机:PopcornPopper.java
  • 电影院类:HomeTheaterFacade.java
代码语言:txt
复制
```java
代码语言:txt
复制
/**
代码语言:txt
复制
 * 一键观影
 */
public void watchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
}
```
  • 最后测试:一键观影:
代码语言:txt
复制
```java
代码语言:txt
复制
new HomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();
代码语言:txt
复制
```

9. 模板方法模式

定义:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况
  • 模板方法模式中的三类角色
  • 1、具体方法(Concrete Method)
  • 2、抽象方法(Abstract Method)
  • 3、钩子方法(Hook Method)
  • 工人的超类:Worker.java
代码语言:txt
复制
```java
代码语言:txt
复制
// 具体方法
代码语言:txt
复制
public final void workOneDay() {
代码语言:txt
复制
    Log.e("workOneDay", "-----------------work start----------------");
代码语言:txt
复制
    enterCompany();
代码语言:txt
复制
    work();
代码语言:txt
复制
    exitCompany();
代码语言:txt
复制
    Log.e("workOneDay", "-----------------work end----------------");
代码语言:txt
复制
}
代码语言:txt
复制
// 工作  抽象方法
代码语言:txt
复制
public abstract void work();
代码语言:txt
复制
// 钩子方法
代码语言:txt
复制
public boolean isNeedPrintDate() {
代码语言:txt
复制
    return false;
代码语言:txt
复制
}
代码语言:txt
复制
private void exitCompany() {
代码语言:txt
复制
    if (isNeedPrintDate()) {
代码语言:txt
复制
        Log.e("exitCompany", "---" + new Date().toLocaleString() + "--->");
代码语言:txt
复制
    }
代码语言:txt
复制
    Log.e("exitCompany", name + "---离开公司");
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
/**
代码语言:txt
复制
 * 重写父类的此方法,使可以查看离开公司时间
 */
@Override
public boolean isNeedPrintDate() {
    return true;
}
```最后测试:
		- 查看所有人员的工作情况:
	
代码语言:txt
复制
	```java
代码语言:txt
复制
	QAWorker qaWorker = new QAWorker("测试人员");
代码语言:txt
复制
    qaWorker();
代码语言:txt
复制
    HRWorker hrWorker = new HRWorker("莉莉姐");
代码语言:txt
复制
    hrWorker.workOneDay();
代码语言:txt
复制
    ...
代码语言:txt
复制
	```
代码语言:txt
复制
- 查看程序猿离开公司的时间:
	
代码语言:txt
复制
	```java
代码语言:txt
复制
	ITWorker itWorker = new ITWorker("jingbin");
代码语言:txt
复制
   itWorker.workOneDay();
代码语言:txt
复制
	```

10. 状态模式

定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。
  • 需求:已自动售货机为例(有已投币、未投币等状态和投币、投币等方法)
  • 最初实现待改进的售货机:VendingMachine.java
  • 改进后的售货机(更具有延展性):VendingMachineBetter.java
代码语言:txt
复制
```java
代码语言:txt
复制
// 放钱
代码语言:txt
复制
public void insertMoney() {
代码语言:txt
复制
    currentState.insertMoney();
代码语言:txt
复制
}
代码语言:txt
复制
// 退钱
代码语言:txt
复制
public void backMoney() {
代码语言:txt
复制
    currentState.backMoney();
代码语言:txt
复制
}
代码语言:txt
复制
// 转动曲柄
代码语言:txt
复制
public void turnCrank() {
代码语言:txt
复制
    currentState.turnCrank();
代码语言:txt
复制
    if (currentState == soldState || currentState == winnerState) {
代码语言:txt
复制
        currentState.dispense();//两种情况会出货
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
// 出商品
代码语言:txt
复制
public void dispense() {
代码语言:txt
复制
    Log.e("VendingMachineBetter", "---发出一件商品");
代码语言:txt
复制
    if (count > 0) {
代码语言:txt
复制
        count--;
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
// 设置对应状态
代码语言:txt
复制
public void setState(State state) {
代码语言:txt
复制
    this.currentState = state;
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
// 初始化售货机,且里面有3个商品

VendingMachineBetter machineBetter = new VendingMachineBetter(3);

machineBetter.insertMoney();

machineBetter.turnCrank();

代码语言:txt
复制
```

11. 建造者模式

建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。

  • 需求:用户去汽车店购买汽车。
  • 分析:汽车店根据每个用户的需求提取对应汽车
  • 建造者超类:Builder
代码语言:txt
复制
```java
代码语言:txt
复制
public abstract class Builder {
代码语言:txt
复制
    public abstract void setPart(String name, String type);
代码语言:txt
复制
    public abstract Product getProduct();
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class ConcreteBuilder extends Builder {
代码语言:txt
复制
    private Product product = new Product();
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void setPart(String name, String type) {
代码语言:txt
复制
        product.setName(name);
代码语言:txt
复制
        product.setType(type);
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public Product getProduct() {
代码语言:txt
复制
        return product;
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
// 店长
代码语言:txt
复制
Director director = new Director();
代码语言:txt
复制
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
代码语言:txt
复制
Product product = director.getBProduct();
代码语言:txt
复制
// 展示汽车信息
代码语言:txt
复制
product.showProduct();
代码语言:txt
复制
```

12. 原型模式

原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

以获取多种形状为例,共分四步:

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)
代码语言:txt
复制
```java
代码语言:txt
复制
public abstract class Shape implements Cloneable {
代码语言:txt
复制
    private String id;
代码语言:txt
复制
    protected String type;
代码语言:txt
复制
    public abstract void draw();
代码语言:txt
复制
    public String getId() {
代码语言:txt
复制
        return id;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setId(String id) {
代码语言:txt
复制
        this.id = id;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public Object clone() {
代码语言:txt
复制
        Object object = null;
代码语言:txt
复制
        try {
代码语言:txt
复制
            object = super.clone();
代码语言:txt
复制
        } catch (CloneNotSupportedException e) {
代码语言:txt
复制
            Log.e("--", e.getMessage());
代码语言:txt
复制
        }
代码语言:txt
复制
        return object;
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class Circle extends Shape {
代码语言:txt
复制
    public Circle() {
代码语言:txt
复制
        type = "Circle";
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void draw() {
代码语言:txt
复制
        Log.e("---", "Inside Circle::draw() method.");
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache
代码语言:txt
复制
```java
代码语言:txt
复制
public class ShapeCache {
代码语言:txt
复制
    private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
代码语言:txt
复制
    public static Shape getShape(String shapeId) {
代码语言:txt
复制
        Shape shapeCache = shapeMap.get(shapeId);
代码语言:txt
复制
        return (Shape) shapeCache.clone();
代码语言:txt
复制
    }
代码语言:txt
复制
    // 对每种形状都运行数据库查询,并创建该形状
代码语言:txt
复制
    // shapeMap.put(shapeKey, shape);
代码语言:txt
复制
    // 例如,我们要添加三种形状
代码语言:txt
复制
    public static void loadCache() {
代码语言:txt
复制
        Circle circle = new Circle();
代码语言:txt
复制
        circle.setId("1");
代码语言:txt
复制
        shapeMap.put(circle.getId(), circle);
代码语言:txt
复制
        Rectangle rectangle = new Rectangle();
代码语言:txt
复制
        rectangle.setId("2");
代码语言:txt
复制
        shapeMap.put(rectangle.getId(), rectangle);
代码语言:txt
复制
        Square square = new Square();
代码语言:txt
复制
        square.setId("3");
代码语言:txt
复制
        shapeMap.put(square.getId(), square);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
代码语言:txt
复制
```java
代码语言:txt
复制
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

ShapeCache.loadCache();

Shape shapeCache1 = ShapeCache.getShape("1");

Shape shapeCache2 = ShapeCache.getShape("2");

Shape shapeCache3 = ShapeCache.getShape("3");

代码语言:txt
复制
```

13. 享元模式

主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。

  • 主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

以随机获取多种形状为例,共分四步:

  • 1、创建一个接口。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface Shape {
代码语言:txt
复制
    void draw();
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建实现接口的实体类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class Circle implements Shape {
代码语言:txt
复制
    private String color;
代码语言:txt
复制
    private int x;
代码语言:txt
复制
    private int y;
代码语言:txt
复制
    private int radius;
代码语言:txt
复制
    public Circle(String color) {
代码语言:txt
复制
        this.color = color;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setX(int x) {
代码语言:txt
复制
        this.x = x;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setY(int y) {
代码语言:txt
复制
        this.y = y;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setRadius(int radius) {
代码语言:txt
复制
        this.radius = radius;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void draw() {
代码语言:txt
复制
        Log.e("---", "Circle: Draw() [Color : " + color
代码语言:txt
复制
                + ", x : " + x + ", y :" + y + ", radius :" + radius);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。
代码语言:txt
复制
```java
代码语言:txt
复制
public class ShapeFactory {
代码语言:txt
复制
    private static final HashMap<String, Shape> circleMap = new HashMap<String, Shape>();
代码语言:txt
复制
    public static Shape getShape(String color) {
代码语言:txt
复制
        Shape shape = circleMap.get(color);
代码语言:txt
复制
        if (shape == null) {
代码语言:txt
复制
            shape = new Circle(color);
代码语言:txt
复制
            circleMap.put(color, shape);
代码语言:txt
复制
            Log.e("getShape", "Creating circle of color : " + color);
代码语言:txt
复制
        }
代码语言:txt
复制
        return shape;
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。
代码语言:txt
复制
```java
代码语言:txt
复制
for (int i = 0; i < 20; i++) {
代码语言:txt
复制
    Circle circle = (Circle) ShapeFactory.getShape(getRandomColor());
代码语言:txt
复制
    circle.setX(getRandomX());
代码语言:txt
复制
    circle.setY(getRandomY());
代码语言:txt
复制
    circle.setRadius(100);
代码语言:txt
复制
    circle.draw();
代码语言:txt
复制
}
代码语言:txt
复制
```

14. 代理模式

一个类代表另一个类的功能。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。可以理解为内存中没有这个对象就创建,有就直接返回这个对象。

  • 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

以获取磁盘中的图片为例,总共分三步:

  • 1、创建一个接口。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface Image {
代码语言:txt
复制
   void display();
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。
代码语言:txt
复制
```java
代码语言:txt
复制
public class RealImage implements Image {
代码语言:txt
复制
    private String fileName;
代码语言:txt
复制
    public RealImage(String fileName) {
代码语言:txt
复制
        this.fileName = fileName;
代码语言:txt
复制
        loadFromDisk(fileName);
代码语言:txt
复制
    }
代码语言:txt
复制
    private void loadFromDisk(String fileName) {
代码语言:txt
复制
        Log.e("RealImage", "loading " + fileName);
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void display() {
代码语言:txt
复制
        Log.e("RealImage", "Displaying " + fileName);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class ProxyImage implements Image {
代码语言:txt
复制
    private String fileName;
代码语言:txt
复制
    private RealImage realImage;
代码语言:txt
复制
    public ProxyImage(String fileName) {
代码语言:txt
复制
        this.fileName = fileName;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void display() {
代码语言:txt
复制
        if (realImage == null) {
代码语言:txt
复制
            realImage = new RealImage(fileName);
代码语言:txt
复制
        }
代码语言:txt
复制
        realImage.display();
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
代码语言:txt
复制
```java
代码语言:txt
复制
Image image = new ProxyImage("test_10mb.png");
代码语言:txt
复制
// 第一次是new的,图像从磁盘加载

image.display();

// 第二次取缓存,图像不需要从磁盘加载

image.display();

代码语言:txt
复制
```

15. 桥接模式

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

  • 主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

以画不同颜色的圆为例,实现共分五步:

  • 1、创建桥接实现接口。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface DrawAPI {
代码语言:txt
复制
    void drawCircle(int radius, int x, int y);
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class RedCircle implements DrawAPI {
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void drawCircle(int radius, int x, int y) {
代码语言:txt
复制
        Log.e("---", "Drawing Circle[ color: red, radius: "
代码语言:txt
复制
                + radius + ", x: " + x + ", " + y + "]");
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、使用 DrawAPI 接口创建抽象类 Shape
代码语言:txt
复制
```java
代码语言:txt
复制
public abstract class Shape {
代码语言:txt
复制
    protected DrawAPI drawAPI;
代码语言:txt
复制
    protected Shape(DrawAPI drawAPI) {
代码语言:txt
复制
        this.drawAPI = drawAPI;
代码语言:txt
复制
    }
代码语言:txt
复制
    public abstract void draw();
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 4、创建实现了 Shape 接口的实体类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class Circle extends Shape {
代码语言:txt
复制
    private int x, y, radius;
代码语言:txt
复制
    protected Circle(int x, int y, int radius, DrawAPI drawAPI) {
代码语言:txt
复制
        super(drawAPI);
代码语言:txt
复制
        this.x = x;
代码语言:txt
复制
        this.y = y;
代码语言:txt
复制
        this.radius = radius;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void draw() {
代码语言:txt
复制
        drawAPI.drawCircle(radius, x, y);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。
代码语言:txt
复制
```java
代码语言:txt
复制
// 画红圆
代码语言:txt
复制
Circle circle = new Circle(10, 10, 100, new RedCircle());s
代码语言:txt
复制
circle.draw();
代码语言:txt
复制
// 画绿圆
代码语言:txt
复制
Circle circle2 = new Circle(20, 20, 100, new GreenCircle());
代码语言:txt
复制
circle2.draw();
代码语言:txt
复制
```

16. 组合模式

又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

  • 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

以创建和打印员工的层次结构为例,最小单元示例:

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。
代码语言:txt
复制
```java
代码语言:txt
复制
public class Employee {
代码语言:txt
复制
    private String name;
代码语言:txt
复制
    // 部门
代码语言:txt
复制
    private String dept;
代码语言:txt
复制
    // 工资
代码语言:txt
复制
    private int salary;
代码语言:txt
复制
    // 员工 list
代码语言:txt
复制
    private List<Employee> subordinates;
代码语言:txt
复制
    public Employee(String name, String dept, int salary) {
代码语言:txt
复制
        this.name = name;
代码语言:txt
复制
        this.dept = dept;
代码语言:txt
复制
        this.salary = salary;
代码语言:txt
复制
        this.subordinates = new ArrayList<Employee>();
代码语言:txt
复制
    }
代码语言:txt
复制
    public void add(Employee e) {
代码语言:txt
复制
        subordinates.add(e);
代码语言:txt
复制
    }
代码语言:txt
复制
    public void remove(Employee e) {
代码语言:txt
复制
        subordinates.remove(e);
代码语言:txt
复制
    }
代码语言:txt
复制
    public List<Employee> getSubordinates() {
代码语言:txt
复制
        return subordinates;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public String toString() {
代码语言:txt
复制
        return "Employee{" +
代码语言:txt
复制
                "name='" + name + '\'' +
代码语言:txt
复制
                ", dept='" + dept + '\'' +
代码语言:txt
复制
                ", salary=" + salary +
代码语言:txt
复制
                ", subordinates=" + subordinates +
代码语言:txt
复制
                '}';
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2.使用 Employee 类来创建和打印员工的层次结构。
代码语言:txt
复制
```java
代码语言:txt
复制
final Employee ceo = new Employee("John", "CEO", 30000);
代码语言:txt
复制
Employee headSales = new Employee("Robert", "Head sales", 20000);
代码语言:txt
复制
Employee headMarketing = new Employee("Michel", "Head Marketing", 20000);
代码语言:txt
复制
Employee clerk1 = new Employee("Laura", "Marketing", 10000);
代码语言:txt
复制
Employee clerk2 = new Employee("Bob", "Marketing", 10000);
代码语言:txt
复制
Employee salesExecutive1 = new Employee("Richard", "Sales", 10000);
代码语言:txt
复制
Employee salesExecutive2 = new Employee("Rob", "Sales", 10000);
代码语言:txt
复制
ceo.add(headSales);
代码语言:txt
复制
ceo.add(headMarketing);
代码语言:txt
复制
headSales.add(salesExecutive1);
代码语言:txt
复制
headSales.add(salesExecutive2);
代码语言:txt
复制
headMarketing.add(clerk1);
代码语言:txt
复制
headMarketing.add(clerk2);
代码语言:txt
复制
Log.e("---", ceo.toString());
代码语言:txt
复制
// 打印
代码语言:txt
复制
/*
代码语言:txt
复制
 * Employee{name='John', dept='CEO', salary=30000,
 * subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
 * subordinates=[
 * Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
 * Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
 * Employee{name='Michel', dept='Head Marketing', salary=20000,
 * subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
 * Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
 */
```

17. 迭代器模式

Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。

  • 主要解决:不同的方式来遍历整个整合对象。

以使用迭代器打印名字为例,总共分三步:

  • 1、创建接口:
代码语言:txt
复制
```java
代码语言:txt
复制
public interface Iterator {
代码语言:txt
复制
    public boolean hasNext();
代码语言:txt
复制
    public Object next();
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public interface Container {
代码语言:txt
复制
    public Iterator getIterator();
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。
代码语言:txt
复制
```java
代码语言:txt
复制
public class NameRepository implements Container {
代码语言:txt
复制
    private String names[] = {"John", "jingbin", "youlookwhat", "lookthis"};
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public Iterator getIterator() {
代码语言:txt
复制
        return new NameIterator();
代码语言:txt
复制
    }
代码语言:txt
复制
    private class NameIterator implements Iterator {
代码语言:txt
复制
        int index;
代码语言:txt
复制
        @Override
代码语言:txt
复制
        public boolean hasNext() {
代码语言:txt
复制
            if (index < names.length) {
代码语言:txt
复制
                return true;
代码语言:txt
复制
            }
代码语言:txt
复制
            return false;
代码语言:txt
复制
        }
代码语言:txt
复制
        @Override
代码语言:txt
复制
        public Object next() {
代码语言:txt
复制
            if (hasNext()) {
代码语言:txt
复制
                return names[index++];
代码语言:txt
复制
            }
代码语言:txt
复制
            return null;
代码语言:txt
复制
        }
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、使用 NameRepository 来获取迭代器,并打印名字。
代码语言:txt
复制
```java
代码语言:txt
复制
NameRepository nameRepository = new NameRepository();
代码语言:txt
复制
for (Iterator iterator = nameRepository.getIterator(); iterator.hasNext(); ) {
代码语言:txt
复制
    String name = (String) iterator.next();
代码语言:txt
复制
    Log.e("---", name);
代码语言:txt
复制
    /*
代码语言:txt
复制
     * /---: John
     * /---: jingbin
     * /---: youlookwhat
     * /---: lookthis
     */
}
```

18. 中介者模式

用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

  • 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。

以公共聊天室为例,最小单元示例步骤:

  • 1、创建中介类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class CharRoom {
代码语言:txt
复制
    public static void showMessage(User user, String message) {
代码语言:txt
复制
        Log.e("---", new Date().toString()
代码语言:txt
复制
                + " [" + user.getName() + "] : " + message);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建 user 类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class User {
代码语言:txt
复制
    private String name;
代码语言:txt
复制
    public User(String name) {
代码语言:txt
复制
        this.name = name;
代码语言:txt
复制
    }
代码语言:txt
复制
    public String getName() {
代码语言:txt
复制
        return name;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setName(String name) {
代码语言:txt
复制
        this.name = name;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void sendMessage(String message) {
代码语言:txt
复制
    	  // 使用中介类
代码语言:txt
复制
        CharRoom.showMessage(this, message);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、使用 User 对象来显示他们之间的通信。
代码语言:txt
复制
```java
代码语言:txt
复制
    User jingbin = new User("jingbin");
代码语言:txt
复制
    jingbin.sendMessage("Hi~ youlookwhat!");
代码语言:txt
复制
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
代码语言:txt
复制
    User jingbin = new User("youlookwhat");
代码语言:txt
复制
    jingbin.sendMessage("Hi~ jingbin!");
代码语言:txt
复制
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
代码语言:txt
复制
```

19. 备忘录模式

保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。

  • 主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

以使用备忘录为例,最小单元步骤:

  • 1、创建 备忘录 Memento 类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class Memento {
代码语言:txt
复制
	private String state;
代码语言:txt
复制
	public Memento(String state) {
代码语言:txt
复制
	    this.state = state;
代码语言:txt
复制
	}
代码语言:txt
复制
	public String getState() {
代码语言:txt
复制
	    return state;
代码语言:txt
复制
	}
代码语言:txt
复制
	public void setState(String state) {
代码语言:txt
复制
	    this.state = state;
代码语言:txt
复制
	}
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建 Originator 类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class Originator {
代码语言:txt
复制
    private String state;
代码语言:txt
复制
    public String getState() {
代码语言:txt
复制
        return state;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void setState(String state) {
代码语言:txt
复制
        this.state = state;
代码语言:txt
复制
    }
代码语言:txt
复制
    public Memento setSateToMemento() {
代码语言:txt
复制
        return new Memento(state);
代码语言:txt
复制
    }
代码语言:txt
复制
    public String getStateFromMemento(Memento memento) {
代码语言:txt
复制
        return memento.getState();
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、创建 CareTaker 类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class CareTaker {
代码语言:txt
复制
    private List<Memento> mementoList = new ArrayList<Memento>();
代码语言:txt
复制
    public void add(Memento memento) {
代码语言:txt
复制
        mementoList.add(memento);
代码语言:txt
复制
    }
代码语言:txt
复制
    public Memento get(int index) {
代码语言:txt
复制
        return mementoList.get(index);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 4、使用 CareTaker 和 Originator 对象。
代码语言:txt
复制
```java

// 管理者

代码语言:txt
复制
CareTaker careTaker = new CareTaker();
代码语言:txt
复制
Originator originator = new Originator();
代码语言:txt
复制
originator.setState("State #1");
代码语言:txt
复制
originator.setState("State #2");
代码语言:txt
复制
// 保存状态
代码语言:txt
复制
careTaker.add(originator.setSateToMemento());
代码语言:txt
复制
originator.setState("State #3");
代码语言:txt
复制
// 保存状态
代码语言:txt
复制
careTaker.add(originator.setSateToMemento());
代码语言:txt
复制
originator.setState("State #4");
代码语言:txt
复制
Log.e("---", "Current State: " + originator.getState());
代码语言:txt
复制
// 得到保存的状态
代码语言:txt
复制
String fromMemento1 = originator.getStateFromMemento(careTaker.get(0));
代码语言:txt
复制
Log.e("---", "First Saved State: " + fromMemento1);
代码语言:txt
复制
String fromMemento2 = originator.getStateFromMemento(careTaker.get(1));
代码语言:txt
复制
Log.e("---", "Second Saved State: " + fromMemento2);
代码语言:txt
复制
/*
代码语言:txt
复制
 * /---: Current State: State #4
 * /---: First Saved State: State #2
 * /---: Second Saved State: State #3
 */
```

20. 解释器模式

提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

  • 主要解决:对于一些固定文法构建一个解释句子的解释器。

以解释一句话为例,最小单元步骤:

  • 1、创建一个表达式接口 Expression。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface Expression {
代码语言:txt
复制
    public boolean interpreter(String content);
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。
代码语言:txt
复制
```java
代码语言:txt
复制
public class TerminalExpression implements Expression {
代码语言:txt
复制
	private String data;
代码语言:txt
复制
	public TerminalExpression(String data) {
代码语言:txt
复制
	    this.data = data;
代码语言:txt
复制
	}
代码语言:txt
复制
	@Override
代码语言:txt
复制
	public boolean interpreter(String content) {
代码语言:txt
复制
	   // 是包含判断
代码语言:txt
复制
	    return content.contains(data);
代码语言:txt
复制
	}
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class OrExpression implements Expression {
代码语言:txt
复制
    private Expression expression1;
代码语言:txt
复制
    private Expression expression2;
代码语言:txt
复制
    public OrExpression(Expression expression1, Expression expression2) {
代码语言:txt
复制
        this.expression1 = expression1;
代码语言:txt
复制
        this.expression2 = expression2;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public boolean interpreter(String content) {
代码语言:txt
复制
        return expression1.interpreter(content) || expression2.interpreter(content);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class AndExpression implements Expression {
代码语言:txt
复制
    private Expression expression1;
代码语言:txt
复制
    private Expression expression2;
代码语言:txt
复制
    public AndExpression(Expression expression1, Expression expression2) {
代码语言:txt
复制
        this.expression1 = expression1;
代码语言:txt
复制
        this.expression2 = expression2;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public boolean interpreter(String content) {
代码语言:txt
复制
        return expression1.interpreter(content) && expression2.interpreter(content);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、使用 Expression 类来创建规则,并解析它们。
代码语言:txt
复制
```java
代码语言:txt
复制
/**
代码语言:txt
复制
 * 规则:jingbin 和 youlookwhat 是男性
 */
public static Expression getMaleExpression() {
    TerminalExpression jingbin = new TerminalExpression("jingbin");
    TerminalExpression youlookwhat = new TerminalExpression("youlookwhat");
    return new OrExpression(jingbin, youlookwhat);
}
代码语言:txt
复制
/**
代码语言:txt
复制
 * 规则:Julie 是一个已婚的女性
 */
public static Expression getMarriedWomanExpression() {
    TerminalExpression julie = new TerminalExpression("Julie");
    TerminalExpression married = new TerminalExpression("Married");
    return new AndExpression(julie, married);
}
代码语言:txt
复制
Expression maleExpression = getMaleExpression();
代码语言:txt
复制
// jingbin is male: true
代码语言:txt
复制
Log.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
代码语言:txt
复制
Expression womanExpression = getMarriedWomanExpression();
代码语言:txt
复制
// Julie is married woman: true
代码语言:txt
复制
Log.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));
代码语言:txt
复制
```

21. 责任链模式

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

  • 主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

以Android Studio中打印日志为例,最小单元步骤:

  • 1、创建抽象的记录器类 AbstractLogger。
代码语言:txt
复制
```java
代码语言:txt
复制
public abstract class AbstractLogger {
代码语言:txt
复制
    public static int INFO = 1;
代码语言:txt
复制
    public static int DEBUG = 2;
代码语言:txt
复制
    public static int ERROR = 3;
代码语言:txt
复制
    protected int level;
代码语言:txt
复制
    // 责任链中的下一个元素
代码语言:txt
复制
    protected AbstractLogger nextLogger;
代码语言:txt
复制
    public void setNextLogger(AbstractLogger nextLogger) {
代码语言:txt
复制
        this.nextLogger = nextLogger;
代码语言:txt
复制
    }
代码语言:txt
复制
    public void logMessage(int level, String message) {
代码语言:txt
复制
        if (this.level <= level) {
代码语言:txt
复制
            write(message);
代码语言:txt
复制
        }
代码语言:txt
复制
        // 递归效果,不断调用下一级 logMessage
代码语言:txt
复制
        if (nextLogger != null) {
代码语言:txt
复制
            nextLogger.logMessage(level, message);
代码语言:txt
复制
        }
代码语言:txt
复制
    }
代码语言:txt
复制
    protected abstract void write(String message);
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 2、创建扩展了该记录器类的实体类。
代码语言:txt
复制
```java
代码语言:txt
复制
public class ConsoleLogger extends AbstractLogger {
代码语言:txt
复制
    public ConsoleLogger(int level) {
代码语言:txt
复制
        this.level = level;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    protected void write(String message) {
代码语言:txt
复制
        Log.e("---", "Standard Console::Logger  " + message);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class FileLogger extends AbstractLogger {
代码语言:txt
复制
    public FileLogger(int level) {
代码语言:txt
复制
        this.level = level;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    protected void write(String message) {
代码语言:txt
复制
        Log.e("---", "File::Logger  " + message);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class ErrorLogger extends AbstractLogger {
代码语言:txt
复制
    public ErrorLogger(int level) {
代码语言:txt
复制
        this.level = level;
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    protected void write(String message) {
代码语言:txt
复制
        Log.e("---", "Error Console::Logger  " + message);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
代码语言:txt
复制
```java
代码语言:txt
复制
public static AbstractLogger getChainOfLoggers() {
代码语言:txt
复制
    ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
代码语言:txt
复制
    FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
代码语言:txt
复制
    ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
代码语言:txt
复制
    errorLogger.setNextLogger(fileLogger);
代码语言:txt
复制
    fileLogger.setNextLogger(consoleLogger);
代码语言:txt
复制
    return errorLogger;
代码语言:txt
复制
}
代码语言:txt
复制
AbstractLogger logger = getChainOfLoggers();
代码语言:txt
复制
// ---: Standard Console::Logger  this is an information.
代码语言:txt
复制
logger.logMessage(AbstractLogger.INFO, "this is an information.");
代码语言:txt
复制
// ---: File::Logger  this is a debug level information.
代码语言:txt
复制
// ---: Standard Console::Logger  this is a debug level information.
代码语言:txt
复制
logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
代码语言:txt
复制
// ---: Error Console::Logger  this is a error level information.
代码语言:txt
复制
// ---: File::Logger  this is a error level information.
代码语言:txt
复制
// ---: Standard Console::Logger  this is a error level information.
代码语言:txt
复制
logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");
代码语言:txt
复制
```

22. 访问者模式

在访问者模式中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

  • 主要解决:稳定的数据结构和易变的操作耦合问题。

以显示计算机的组成部分为例,主要分五步实现:

  • 1、定义一个表示元素的接口。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface ComputerPart {
代码语言:txt
复制
    public void accept(ComputerPartVisitor computerPartVisitor);
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class Computer implements ComputerPart {
代码语言:txt
复制
    private ComputerPart[] parts;
代码语言:txt
复制
    public Computer() {
代码语言:txt
复制
        this.parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void accept(ComputerPartVisitor computerPartVisitor) {
代码语言:txt
复制
        for (ComputerPart part : parts) {
代码语言:txt
复制
            part.accept(computerPartVisitor);
代码语言:txt
复制
        }
代码语言:txt
复制
        computerPartVisitor.visit(this);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
代码语言:txt
复制
```java
代码语言:txt
复制
public class Mouse implements ComputerPart {
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void accept(ComputerPartVisitor computerPartVisitor) {
代码语言:txt
复制
        computerPartVisitor.visit(this);
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 3、定义一个表示访问者的接口。
代码语言:txt
复制
```java
代码语言:txt
复制
public interface ComputerPartVisitor {
代码语言:txt
复制
    public void visit(Computer computer);
代码语言:txt
复制
    public void visit(Mouse mouse);
代码语言:txt
复制
    public void visit(Keyboard keyboard);
代码语言:txt
复制
    public void visit(Monitor monitor);
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 4、创建实现了上述类的实体访问者。
代码语言:txt
复制
```java
代码语言:txt
复制
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void visit(Computer computer) {
代码语言:txt
复制
        Log.e("---", "Displaying Computer.");
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void visit(Mouse mouse) {
代码语言:txt
复制
        Log.e("---", "Displaying Mouse.");
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void visit(Keyboard keyboard) {
代码语言:txt
复制
        Log.e("---", "Displaying Keyboard.");
代码语言:txt
复制
    }
代码语言:txt
复制
    @Override
代码语言:txt
复制
    public void visit(Monitor monitor) {
代码语言:txt
复制
        Log.e("---", "Displaying Monitor.");
代码语言:txt
复制
    }
代码语言:txt
复制
}
代码语言:txt
复制
```
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
代码语言:txt
复制
```java
代码语言:txt
复制
    ComputerPart computer = new Computer();
代码语言:txt
复制
    computer.accept(new ComputerPartDisplayVisitor());
代码语言:txt
复制
    /*
代码语言:txt
复制
     *打印:
代码语言:txt
复制
     *---: Displaying Mouse.
代码语言:txt
复制
     *---: Displaying Keyboard.
代码语言:txt
复制
     *---: Displaying Monitor.
代码语言:txt
复制
     *---: Displaying Computer.
代码语言:txt
复制
     */
代码语言:txt
复制
```

Download

Reference

About me

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Blog Catalogue:
  • Source Code
  • Project Picture
  • Pattern Analysis
    • 1. 观察者模式
      • 2. 工厂模式
        • 3. 单例设计模式
          • 4. 策略模式
            • 5. 适配器模式
              • 6. 命令模式
                • 7. 装饰者模式
                  • 8. 外观模式
                    • 9. 模板方法模式
                      • 10. 状态模式
                        • 11. 建造者模式
                          • 12. 原型模式
                            • 13. 享元模式
                              • 14. 代理模式
                                • 15. 桥接模式
                                  • 16. 组合模式
                                    • 17. 迭代器模式
                                      • 18. 中介者模式
                                        • 19. 备忘录模式
                                          • 20. 解释器模式
                                            • 21. 责任链模式
                                              • 22. 访问者模式
                                              • Download
                                              • Reference
                                              • About me
                                              领券
                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档