Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

DesignPattern

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

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

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


Blog Catalogue:

Source Code

Project Picture

Pattern Analysis

1. 观察者模式

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

  • 对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

  • 专题接口:Subject.java ;

    /** * 注册一个观察者 */publicvoidregisterObserver(Observerobserver);
    /** * 移除一个观察者 */publicvoidremoveObserver(Observerobserver);
    /** * 通知所有观察者 */publicvoidnotifyObservers();
  • 3D服务号的实现类:ObjectFor3D.java

    @OverridepublicvoidregisterObserver(Observerobserver) {
    observers.add(observer);
    }
    @OverridepublicvoidremoveObserver(Observerobserver) {
    intindex = observers.indexOf(observer);
    if (index >= 0) {
    observers.remove(index);
    }
    }
    @OverridepublicvoidnotifyObservers() {
    for (Observerobserver : observers) {
    observer.update(msg);
    }
    }
    /** * 主题更新信息 */publicvoidsetMsg(Stringmsg) {
    this.msg = msg;
    notifyObservers();
    }
  • 所有观察者需要实现此接口:Observer.java

    publicObserverUser1(Subjectsubject) {
    subject.registerObserver(this);
    }
    @Overridepublicvoidupdate(Stringmsg) {
    Log.e("-----ObserverUser1 ", "得到 3D 号码:" + msg + ", 我要记下来。");
    }
  • 最后测试:ObserverActivity.java

    // 创建服务号objectFor3D = newObjectFor3D();
    // 创建两个订阅者observerUser1 = newObserverUser1(objectFor3D);
    observerUser2 = newObserverUser2(objectFor3D);
    // 两个观察者,发送两条信息objectFor3D.setMsg("201610121 的3D号为:127");
    objectFor3D.setMsg("20161022 的3D号为:000");

2. 工厂模式

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

  • 1、静态工厂模式

    • 这个最常见了,项目中的辅助类,TextUtil.isEmpty等,类+静态方法。
  • 2、简单工厂模式(店里买肉夹馍)

    • 定义:通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
    • 根据类型直接创建肉夹馍:SimpleRoujiaMoFactory.java
    publicRoujiaMocreatRoujiaMo(Stringtype) {
    RoujiaMoroujiaMo = null;
    switch (type) {
    case"Suan":
    roujiaMo = newZSuanRoujiaMo();
    break;
    case"La":
    roujiaMo = newZLaRoujiaMo();
    break;
    case"Tian":
    roujiaMo = newZTianRoujiaMo();
    break;
    default:// 默认为酸肉夹馍roujiaMo = newZSuanRoujiaMo();
    break;
    }
    returnroujiaMo;
    }
  • 3、工厂方法模式(开分店)

    • 定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。
    • 对比定义:
    • 1、定义了创建对象的一个接口:public abstract RouJiaMo sellRoujiaMo(String type);
    • 2、由子类决定实例化的类,可以看到我们的馍是子类生成的。
  • 提供创建肉夹馍店抽象方法:RoujiaMoStore.java

    publicabstractRoujiaMosellRoujiaMo(Stringtype);
  • 具体实现抽象方法:XianRoujiaMoStore.java

  • 分店依旧使用简单工厂模式:XianSimpleRoujiaMoFactory.java

  • 4、抽象工厂模式(使用官方提供的原料)

    • 定义:提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
    • 对比定义:
      • 1、提供一个接口:public interface RouJiaMoYLFactroy
      • 2、用于创建相关的或依赖对象的家族 public Meat createMeat();public YuanLiao createYuanliao();我们接口用于创建一系列的原材料。
    • 创建用于提供原料的接口工厂:RoujiaMoYLFactory.java
    • 各自分店实现接口,完成原料提供:XianRoujiaMoYLFoctory.java
    • 准备时,使用官方的原料:RoujiaMo.java
    /** * 准备工作 */publicvoidprepare(RoujiaMoYLFactoryroujiaMoYLFactory) {
    Meetmeet = roujiaMoYLFactory.creatMeet();
    YuanLiaoyuanLiao = roujiaMoYLFactory.creatYuanLiao();
    Log.e("---RoujiaMo:", "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:"+meet+"yuanLiao:"+yuanLiao);
    }

3. 单例设计模式

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

  • 定义:只需要三步就可以保证对象的唯一性

    • (1) 不允许其他程序用new对象
    • (2) 在该类中创建对象
    • (3) 对外提供一个可以让其他程序获取该对象的方法
  • 对比定义:

    • (1) 私有化该类的构造函数
    • (2) 通过new在本类中创建一个本类对象
    • (3) 定义一个公有的方法,将在该类中所创建的对象返回
  • 饿汉式[可用]:SingletonEHan.java

  • 含懒汉式[双重校验锁 推荐用]:SingletonLanHan.java

privateSingletonLanHan() {}
privatestaticSingletonLanHansingletonLanHanFour;
publicstaticSingletonLanHangetSingletonLanHanFour() {
if (singletonLanHanFour == null) {
synchronized (SingletonLanHan.class) {
if (singletonLanHanFour == null) {
singletonLanHanFour = newSingletonLanHan();
}
}
}
returnsingletonLanHanFour;
}

4. 策略模式

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

  • 以创建游戏角色为例子:
    • 最初的游戏角色的父类:Role.java
    • 发现有重复代码后,重构后的父类:Role.java
  • 总结:
    • 1、封装变化(把可能变化的代码封装起来)
    • 2、多用组合,少用继承(我们使用组合的方式,为客户设置了算法)
    • 3、针对接口编程,不针对实现(对于Role类的设计完全的针对角色,和技能的实现没有关系)
  • 最后测试:创建角色:
RoleAroleA = newRoleA("---A");
roleA.setiDisplayBehavior(newDisplayYZ())
.setiAttackBehavior(newAttackXL())
.setiDefendBehavior(newDefendTMS())
.setiRunBehavior(newRunJCTQ());
roleA.display();// 样子roleA.attack();// 攻击roleA.run();// 逃跑roleA.defend();// 防御

5. 适配器模式

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

  • 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)

  • 一部手机: Mobile.java

  • 手机依赖一个提供5V电压的接口: V5Power.java

  • 我们拥有的是220V家用交流电: V220Power.java

  • 适配器,完成220V转5V的作用V5PowerAdapter.java

  • 最后测试:给手机冲个电:

    Mobilemobile = newMobile();
    V5Powerv5Power = newV5PowerAdapter(newV200Power());
    mobile.inputPower(v5Power);

6. 命令模式

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

  • 需求:最近智能家电很火热,假设现在有电视、电脑、电灯等家电,现在需要你做个遥控器控制所有家电的开关,要求做到每个按钮对应的功能供用户个性化,对于新买入家电要有非常强的扩展性。
  • 1、家电的API:Door.java
  • 2、把命令封装成类:
  • 3、遥控器:ControlPanel.java
  • 4、定义一个命令,可以干一系列的事情:QuickCommand.java
QuickCommandquickCloseCommand = newQuickCommand(newCommand[]{newLightOffCommand(light), newComputerOffCommand(computer), newDoorCloseCommand(door)});
controlPanel.setCommands(6, quickOpenCommand);
controlPanel.keyPressed(6);
controlPanel.setCommands(0, newDoorOpenCommand(door));// 开门controlPanel.keyPressed(0);

7. 装饰者模式

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

  • 先简单描述下装饰者模式发挥作用的地方,当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了。这里还体现了一个原则:类应该对扩展开放,对修改关闭。

  • 需求:设计游戏的装备系统,基本要求,要可以计算出每种装备在镶嵌了各种宝石后的攻击力和描述:

  • 1、装备的超类:IEquip.java

  • 2、各个装备的实现类:

  • 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java

  • 4、装饰品的实现类:

  • 5、最后测试:计算攻击力和查看描述:

    Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
    IEquipiEquip = newRedGemDecorator(newRedGemDecorator(newBlueGemDecorator(newShoeEquip())));
    Log.e("---", "攻击力:" + iEquip.caculateAttack());
    Log.e("---", "描述语:" + iEquip.description());

8. 外观模式

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

  • 需求:我比较喜欢看电影,于是买了投影仪、电脑、音响、设计了房间的灯光、买了爆米花机,然后我想看电影的时候,我需要一键观影和一键关闭。

  • 每个设备类的开关等操作:

  • eg: 爆米花机:PopcornPopper.java

  • 电影院类:HomeTheaterFacade.java

    /** * 一键观影 */publicvoidwatchMovie() {
    computer.on();
    light.down();
    popcornPopper.on();
    popcornPopper.makePopcorn();
    projector.on();
    projector.open();
    player.on();
    player.make3DListener();
    }
  • 最后测试:一键观影:

    newHomeTheaterFacade(computer, light, player, popcornPopper, projector).watchMovie();

9. 模板方法模式

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

  • 需求:简单描述一下:本公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况

  • 模板方法模式中的三类角色

  • 1、具体方法(Concrete Method)

  • 2、抽象方法(Abstract Method)

  • 3、钩子方法(Hook Method)

  • 工人的超类:Worker.java

    // 具体方法publicfinalvoidworkOneDay() {
    Log.e("workOneDay", "-----------------work start----------------");
    enterCompany();
    work();
    exitCompany();
    Log.e("workOneDay", "-----------------work end----------------");
    }
    // 工作 抽象方法publicabstractvoidwork();
    // 钩子方法publicbooleanisNeedPrintDate() {
    returnfalse;
    }
    privatevoidexitCompany() {
    if (isNeedPrintDate()) {
    Log.e("exitCompany", "---" + newDate().toLocaleString() + "--->");
    }
    Log.e("exitCompany", name + "---离开公司");
    }
  • 程序员实现类(可得知时间):ITWorker.java

    /** * 重写父类的此方法,使可以查看离开公司时间 */@OverridepublicbooleanisNeedPrintDate() {
    returntrue;
    }
  • 最后测试:

    • 查看所有人员的工作情况:

      QAWorkerqaWorker = newQAWorker("测试人员");
      qaWorker();
      HRWorkerhrWorker = newHRWorker("莉莉姐");
      hrWorker.workOneDay();
      ...
    • 查看程序猿离开公司的时间:

      ITWorkeritWorker = newITWorker("jingbin");
      itWorker.workOneDay();

10. 状态模式

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

  • 定义又开始模糊了,理一下,当对象的内部状态改变时,它的行为跟随状态的改变而改变了,看起来好像重新初始化了一个类似的。

  • 需求:以自动售货机为例(有已投币、未投币等状态和投币、退币等方法)

  • 最初实现待改进的售货机:VendingMachine.java

  • 改进后的售货机(更具有延展性):VendingMachineBetter.java

    // 放钱publicvoidinsertMoney() {
    currentState.insertMoney();
    }
    // 退钱publicvoidbackMoney() {
    currentState.backMoney();
    }
    // 转动曲柄publicvoidturnCrank() {
    currentState.turnCrank();
    if (currentState == soldState || currentState == winnerState) {
    currentState.dispense();//两种情况会出货
    }
    }
    // 出商品publicvoiddispense() {
    Log.e("VendingMachineBetter", "---发出一件商品");
    if (count > 0) {
    count--;
    }
    }
    // 设置对应状态publicvoidsetState(Statestate) {
    this.currentState = state;
    }
  • 状态的接口:State.java

  • 对应状态的接口实现类:

  • 改进后的售货机测试:

    // 初始化售货机,且里面有3个商品VendingMachineBettermachineBetter = newVendingMachineBetter(3);
    machineBetter.insertMoney();
    machineBetter.turnCrank();

11. 建造者模式

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

  • 需求:用户去汽车店购买汽车。

  • 分析:汽车店根据每个用户的需求提取对应汽车

  • 建造者超类:Builder

    publicabstractclassBuilder {
    publicabstractvoidsetPart(Stringname, Stringtype);
    publicabstractProductgetProduct();
    }
  • 建造者对应实现类:ConcreteBuilder

    publicclassConcreteBuilderextendsBuilder {
    privateProductproduct = newProduct();
    @OverridepublicvoidsetPart(Stringname, Stringtype) {
    product.setName(name);
    product.setType(type);
    }
    @OverridepublicProductgetProduct() {
    returnproduct;
    }
    }
  • 店长Director取汽车:

    // 店长Directordirector = newDirector();
    // 得到宝马汽车,内部实现提取宝马汽车的详情操作Productproduct = director.getBProduct();
    // 展示汽车信息product.showProduct();

12. 原型模式

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

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

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

  • 1、创建一个实现了 Cloneable 接口的抽象类。Shape(implements Cloneable)

    publicabstractclassShapeimplementsCloneable {
    privateStringid;
    protectedStringtype;
    publicabstractvoiddraw();
    publicStringgetId() {
    returnid;
    }
    publicvoidsetId(Stringid) {
    this.id = id;
    }
    @OverridepublicObjectclone() {
    Objectobject = null;
    try {
    object = super.clone();
    } catch (CloneNotSupportedExceptione) {
    Log.e("--", e.getMessage());
    }
    returnobject;
    }
    }
  • 2、创建扩展了上面抽象类的实体类。CircleRectangleSquare

    publicclassCircleextendsShape {
    publicCircle() {
    type = "Circle";
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Inside Circle::draw() method.");
    }
    }
  • 3、创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。ShapeCache

    publicclassShapeCache {
    privatestaticHashtable<String, Shape> shapeMap = newHashtable<String, Shape>();
    publicstaticShapegetShape(StringshapeId) {
    ShapeshapeCache = shapeMap.get(shapeId);
    return (Shape) shapeCache.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状// shapeMap.put(shapeKey, shape);// 例如,我们要添加三种形状publicstaticvoidloadCache() {
    Circlecircle = newCircle();
    circle.setId("1");
    shapeMap.put(circle.getId(), circle);
    Rectanglerectangle = newRectangle();
    rectangle.setId("2");
    shapeMap.put(rectangle.getId(), rectangle);
    Squaresquare = newSquare();
    square.setId("3");
    shapeMap.put(square.getId(), square);
    }
    }
  • 4、使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。

    // 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。ShapeCache.loadCache();
    ShapeshapeCache1 = ShapeCache.getShape("1");
    ShapeshapeCache2 = ShapeCache.getShape("2");
    ShapeshapeCache3 = ShapeCache.getShape("3");

13. 享元模式

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

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

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

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

  • 1、创建一个接口。

    publicinterfaceShape {
    voiddraw();
    }
  • 2、创建实现接口的实体类。

    publicclassCircleimplementsShape {
    privateStringcolor;
    privateintx;
    privateinty;
    privateintradius;
    publicCircle(Stringcolor) {
    this.color = color;
    }
    publicvoidsetX(intx) {
    this.x = x;
    }
    publicvoidsetY(inty) {
    this.y = y;
    }
    publicvoidsetRadius(intradius) {
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    Log.e("---", "Circle: Draw() [Color : " + color
    + ", x : " + x + ", y :" + y + ", radius :" + radius);
    }
    }
  • 3、创建一个工厂,生成基于给定信息的实体类的对象。

    publicclassShapeFactory {
    privatestaticfinalHashMap<String, Shape> circleMap = newHashMap<String, Shape>();
    publicstaticShapegetShape(Stringcolor) {
    Shapeshape = circleMap.get(color);
    if (shape == null) {
    shape = newCircle(color);
    circleMap.put(color, shape);
    Log.e("getShape", "Creating circle of color : " + color);
    }
    returnshape;
    }
    }
  • 4、使用该工厂,通过传递颜色信息来获取实体类的对象。

    for (inti = 0; i < 20; i++) {
    Circlecircle = (Circle) ShapeFactory.getShape(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }

14. 代理模式

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

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

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

  • 1、创建一个接口。

    publicinterfaceImage {
    voiddisplay();
    }
  • 2、创建实现接口的实体类 RealImage。对应代理类:ProxyImage。

    publicclassRealImageimplementsImage {
    privateStringfileName;
    publicRealImage(StringfileName) {
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    privatevoidloadFromDisk(StringfileName) {
    Log.e("RealImage", "loading " + fileName);
    }
    @Overridepublicvoiddisplay() {
    Log.e("RealImage", "Displaying " + fileName);
    }
    }
    publicclassProxyImageimplementsImage {
    privateStringfileName;
    privateRealImagerealImage;
    publicProxyImage(StringfileName) {
    this.fileName = fileName;
    }
    @Overridepublicvoiddisplay() {
    if (realImage == null) {
    realImage = newRealImage(fileName);
    }
    realImage.display();
    }
    }
  • 3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。

    Imageimage = newProxyImage("test_10mb.png");
    // 第一次是new的,图像从磁盘加载image.display();
    // 第二次取缓存,图像不需要从磁盘加载image.display();

15. 桥接模式

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

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

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

  • 1、创建桥接实现接口。

    publicinterfaceDrawAPI {
    voiddrawCircle(intradius, intx, inty);
    }
  • 2、创建实现了 DrawAPI 接口的实体桥接实现类。RedCircleGreenCircle

    publicclassRedCircleimplementsDrawAPI {
    @OverridepublicvoiddrawCircle(intradius, intx, inty) {
    Log.e("---", "Drawing Circle[ color: red, radius: "
    + radius + ", x: " + x + ", " + y + "]");
    }
    }
  • 3、使用 DrawAPI 接口创建抽象类 Shape

    publicabstractclassShape {
    protectedDrawAPIdrawAPI;
    protectedShape(DrawAPIdrawAPI) {
    this.drawAPI = drawAPI;
    }
    publicabstractvoiddraw();
    }
  • 4、创建实现了 Shape 接口的实体类。

    publicclassCircleextendsShape {
    privateintx, y, radius;
    protectedCircle(intx, inty, intradius, DrawAPIdrawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    @Overridepublicvoiddraw() {
    drawAPI.drawCircle(radius, x, y);
    }
    }
  • 5、使用 Shape 和 DrawAPI 类画出不同颜色的圆。

    // 画红圆Circlecircle = newCircle(10, 10, 100, newRedCircle());scircle.draw();
    // 画绿圆Circlecircle2 = newCircle(20, 20, 100, newGreenCircle());
    circle2.draw();

16. 组合模式

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

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

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

  • 1、创建 Employee 类,该类带有 Employee 对象的列表。

    publicclassEmployee {
    privateStringname;
    // 部门privateStringdept;
    // 工资privateintsalary;
    // 员工 listprivateList<Employee> subordinates;
    publicEmployee(Stringname, Stringdept, intsalary) {
    this.name = name;
    this.dept = dept;
    this.salary = salary;
    this.subordinates = newArrayList<Employee>();
    }
    publicvoidadd(Employeee) {
    subordinates.add(e);
    }
    publicvoidremove(Employeee) {
    subordinates.remove(e);
    }
    publicList<Employee> getSubordinates() {
    returnsubordinates;
    }
    @OverridepublicStringtoString() {
    return"Employee{" +
    "name='" + name + '\'' +
    ", dept='" + dept + '\'' +
    ", salary=" + salary +
    ", subordinates=" + subordinates +
    '}';
    }
    }
  • 2.使用 Employee 类来创建和打印员工的层次结构。

    finalEmployeeceo = newEmployee("John", "CEO", 30000);
    EmployeeheadSales = newEmployee("Robert", "Head sales", 20000);
    EmployeeheadMarketing = newEmployee("Michel", "Head Marketing", 20000);
    Employeeclerk1 = newEmployee("Laura", "Marketing", 10000);
    Employeeclerk2 = newEmployee("Bob", "Marketing", 10000);
    EmployeesalesExecutive1 = newEmployee("Richard", "Sales", 10000);
    EmployeesalesExecutive2 = newEmployee("Rob", "Sales", 10000);
    ceo.add(headSales);
    ceo.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    Log.e("---", ceo.toString());
    // 打印/* * 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、创建接口:

    publicinterfaceIterator {
    publicbooleanhasNext();
    publicObjectnext();
    }
    publicinterfaceContainer {
    publicIteratorgetIterator();
    }
  • 2、创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

    publicclassNameRepositoryimplementsContainer {
    privateStringnames[] = {"John", "jingbin", "youlookwhat", "lookthis"};
    @OverridepublicIteratorgetIterator() {
    returnnewNameIterator();
    }
    privateclassNameIteratorimplementsIterator {
    intindex;
    @OverridepublicbooleanhasNext() {
    if (index < names.length) {
    returntrue;
    }
    returnfalse;
    }
    @OverridepublicObjectnext() {
    if (hasNext()) {
    returnnames[index++];
    }
    returnnull;
    }
    }
    }
  • 3、使用 NameRepository 来获取迭代器,并打印名字。

    NameRepositorynameRepository = newNameRepository();
    for (Iteratoriterator = nameRepository.getIterator(); iterator.hasNext(); ) {
    Stringname = (String) iterator.next();
    Log.e("---", name);
    /* * /---: John * /---: jingbin * /---: youlookwhat * /---: lookthis */
    }

18. 中介者模式

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

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

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

  • 1、创建中介类。

    publicclassCharRoom {
    publicstaticvoidshowMessage(Useruser, Stringmessage) {
    Log.e("---", newDate().toString()
    + " [" + user.getName() + "] : " + message);
    }
    }
  • 2、创建 user 类。

    publicclassUser {
    privateStringname;
    publicUser(Stringname) {
    this.name = name;
    }
    publicStringgetName() {
    returnname;
    }
    publicvoidsetName(Stringname) {
    this.name = name;
    }
    publicvoidsendMessage(Stringmessage) {
    // 使用中介类CharRoom.showMessage(this, message);
    }
    }
  • 3、使用 User 对象来显示他们之间的通信。

    Userjingbin = newUser("jingbin");
    jingbin.sendMessage("Hi~ youlookwhat!");
    //---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!Userjingbin = newUser("youlookwhat");
    jingbin.sendMessage("Hi~ jingbin!");
    //---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!

19. 备忘录模式

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

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

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

  • 1、创建 备忘录 Memento 类。

    publicclassMemento {
    privateStringstate;
    publicMemento(Stringstate) {
    this.state = state;
    }
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    }
  • 2、创建 Originator 类。

    publicclassOriginator {
    privateStringstate;
    publicStringgetState() {
    returnstate;
    }
    publicvoidsetState(Stringstate) {
    this.state = state;
    }
    publicMementosetSateToMemento() {
    returnnewMemento(state);
    }
    publicStringgetStateFromMemento(Mementomemento) {
    returnmemento.getState();
    }
    }
  • 3、创建 CareTaker 类。

    publicclassCareTaker {
    privateList<Memento> mementoList = newArrayList<Memento>();
    publicvoidadd(Mementomemento) {
    mementoList.add(memento);
    }
    publicMementoget(intindex) {
    returnmementoList.get(index);
    }
    }
  • 4、使用 CareTaker 和 Originator 对象。

    // 管理者CareTakercareTaker = newCareTaker();
    Originatororiginator = newOriginator();
    originator.setState("State #1");
    originator.setState("State #2");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #3");
    // 保存状态careTaker.add(originator.setSateToMemento());
    originator.setState("State #4");
    Log.e("---", "Current State: " + originator.getState());
    // 得到保存的状态StringfromMemento1 = originator.getStateFromMemento(careTaker.get(0));
    Log.e("---", "First Saved State: " + fromMemento1);
    StringfromMemento2 = originator.getStateFromMemento(careTaker.get(1));
    Log.e("---", "Second Saved State: " + fromMemento2);
    /* * /---: Current State: State #4 * /---: First Saved State: State #2 * /---: Second Saved State: State #3 */

20. 解释器模式

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

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

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

  • 1、创建一个表达式接口 Expression。

    publicinterfaceExpression {
    publicbooleaninterpreter(Stringcontent);
    }
  • 2、创建实现了上述接口的实体类。TerminalExpression、OrExpression、AndExpression。

    publicclassTerminalExpressionimplementsExpression {
    privateStringdata;
    publicTerminalExpression(Stringdata) {
    this.data = data;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    // 是包含判断returncontent.contains(data);
    }
    }
    publicclassOrExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicOrExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) || expression2.interpreter(content);
    }
    }
    publicclassAndExpressionimplementsExpression {
    privateExpressionexpression1;
    privateExpressionexpression2;
    publicAndExpression(Expressionexpression1, Expressionexpression2) {
    this.expression1 = expression1;
    this.expression2 = expression2;
    }
    @Overridepublicbooleaninterpreter(Stringcontent) {
    returnexpression1.interpreter(content) && expression2.interpreter(content);
    }
    }
  • 3、使用 Expression 类来创建规则,并解析它们。

    /** * 规则:jingbin 和 youlookwhat 是男性 */publicstaticExpressiongetMaleExpression() {
    TerminalExpressionjingbin = newTerminalExpression("jingbin");
    TerminalExpressionyoulookwhat = newTerminalExpression("youlookwhat");
    returnnewOrExpression(jingbin, youlookwhat);
    }
    /** * 规则:Julie 是一个已婚的女性 */publicstaticExpressiongetMarriedWomanExpression() {
    TerminalExpressionjulie = newTerminalExpression("Julie");
    TerminalExpressionmarried = newTerminalExpression("Married");
    returnnewAndExpression(julie, married);
    }
    ExpressionmaleExpression = getMaleExpression();
    // jingbin is male: trueLog.e("---", "jingbin is male: " + maleExpression.interpreter("jingbin"));
    ExpressionwomanExpression = getMarriedWomanExpression();
    // Julie is married woman: trueLog.e("---", "Julie is married woman: " + womanExpression.interpreter("Married Julie"));

21. 责任链模式

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

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

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

  • 1、创建抽象的记录器类 AbstractLogger。

    publicabstractclassAbstractLogger {
    publicstaticintINFO = 1;
    publicstaticintDEBUG = 2;
    publicstaticintERROR = 3;
    protectedintlevel;
    // 责任链中的下一个元素protectedAbstractLoggernextLogger;
    publicvoidsetNextLogger(AbstractLoggernextLogger) {
    this.nextLogger = nextLogger;
    }
    publicvoidlogMessage(intlevel, Stringmessage) {
    if (this.level <= level) {
    write(message);
    }
    // 递归效果,不断调用下一级 logMessageif (nextLogger != null) {
    nextLogger.logMessage(level, message);
    }
    }
    protectedabstractvoidwrite(Stringmessage);
    }
  • 2、创建扩展了该记录器类的实体类。

    publicclassConsoleLoggerextendsAbstractLogger {
    publicConsoleLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Standard Console::Logger " + message);
    }
    }
    publicclassFileLoggerextendsAbstractLogger {
    publicFileLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "File::Logger " + message);
    }
    }
    publicclassErrorLoggerextendsAbstractLogger {
    publicErrorLogger(intlevel) {
    this.level = level;
    }
    @Overrideprotectedvoidwrite(Stringmessage) {
    Log.e("---", "Error Console::Logger " + message);
    }
    }
  • 3、创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。

    publicstaticAbstractLoggergetChainOfLoggers() {
    ErrorLoggererrorLogger = newErrorLogger(AbstractLogger.ERROR);
    FileLoggerfileLogger = newFileLogger(AbstractLogger.DEBUG);
    ConsoleLoggerconsoleLogger = newConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    returnerrorLogger;
    }
    AbstractLoggerlogger = getChainOfLoggers();
    // ---: Standard Console::Logger this is an information.logger.logMessage(AbstractLogger.INFO, "this is an information.");
    // ---: File::Logger this is a debug level information.// ---: Standard Console::Logger this is a debug level information.logger.logMessage(AbstractLogger.DEBUG, "this is a debug level information.");
    // ---: Error Console::Logger this is a error level information.// ---: File::Logger this is a error level information.// ---: Standard Console::Logger this is a error level information.logger.logMessage(AbstractLogger.ERROR, "this is a error level information.");

22. 访问者模式

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

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

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

  • 1、定义一个表示元素的接口。

    publicinterfaceComputerPart {
    publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
    }
  • 2、创建扩展了上述类的实体类。KeyboardMonitorMouseComputer

    publicclassComputerimplementsComputerPart {
    privateComputerPart[] parts;
    publicComputer() {
    this.parts = newComputerPart[]{newMouse(), newKeyboard(), newMonitor()};
    }
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    for (ComputerPartpart : parts) {
    part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }
    publicclassMouseimplementsComputerPart {
    @Overridepublicvoidaccept(ComputerPartVisitorcomputerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
  • 3、定义一个表示访问者的接口。

    publicinterfaceComputerPartVisitor {
    publicvoidvisit(Computercomputer);
    publicvoidvisit(Mousemouse);
    publicvoidvisit(Keyboardkeyboard);
    publicvoidvisit(Monitormonitor);
    }
  • 4、创建实现了上述类的实体访问者。

    publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor {
    @Overridepublicvoidvisit(Computercomputer) {
    Log.e("---", "Displaying Computer.");
    }
    @Overridepublicvoidvisit(Mousemouse) {
    Log.e("---", "Displaying Mouse.");
    }
    @Overridepublicvoidvisit(Keyboardkeyboard) {
    Log.e("---", "Displaying Keyboard.");
    }
    @Overridepublicvoidvisit(Monitormonitor) {
    Log.e("---", "Displaying Monitor.");
    }
    }
  • 5、使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

    ComputerPartcomputer = newComputer();
    computer.accept(newComputerPartDisplayVisitor());
    /* *打印: *---: Displaying Mouse. *---: Displaying Keyboard. *---: Displaying Monitor. *---: Displaying Computer. */

Download

Reference

About me

About

📚 Java 23种设计模式全归纳

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages