行为型设计模式---中介者模式

设计模式

序号内容链接地址
1设计模式七大原则https://blog.csdn.net/qq_39668819/article/details/115390615
2创建型设计模式–工厂模式https://blog.csdn.net/qq_39668819/article/details/115375928
3创建型设计模式–抽象工厂模式https://blog.csdn.net/qq_39668819/article/details/115390992
4创建型设计模式–单例模式https://blog.csdn.net/qq_39668819/article/details/115396191
5创建型设计模式–建造者模式https://blog.csdn.net/qq_39668819/article/details/115396212
6创建型设计模式—原型模式https://blog.csdn.net/qq_39668819/article/details/115396227
7结构型设计模式—代理模式https://blog.csdn.net/qq_39668819/article/details/115480346
8结构型设计模式—适配器模式https://blog.csdn.net/qq_39668819/article/details/115499090
9结构型设计模式—桥接模式https://blog.csdn.net/qq_39668819/article/details/115560823
10结构型设计模式—装饰模式https://blog.csdn.net/qq_39668819/article/details/115582291
11结构型设计模式—外观模式https://blog.csdn.net/qq_39668819/article/details/115643900
12结构型设计模式—享元模式https://blog.csdn.net/qq_39668819/article/details/115680930
13结构型设计模式—组合模式https://blog.csdn.net/qq_39668819/article/details/115720713
14行为型设计模式—模板方法模式https://blog.csdn.net/qq_39668819/article/details/115774426
15行为型设计模式—策略模式https://blog.csdn.net/qq_39668819/article/details/115804292
16行为型设计模式—命令模式https://blog.csdn.net/qq_39668819/article/details/115877361
17行为型设计模式—责任链模式https://blog.csdn.net/qq_39668819/article/details/115981287
18行为型设计模式—状态模式https://blog.csdn.net/qq_39668819/article/details/116077215
19行为型设计模式—观察者模式https://blog.csdn.net/qq_39668819/article/details/116141223
20行为型设计模式—中介者模式https://blog.csdn.net/qq_39668819/article/details/116177694
21行为型设计模式—迭代器模式https://blog.csdn.net/qq_39668819/article/details/116213033
22行为型设计模式—访问者模式https://blog.csdn.net/qq_39668819/article/details/116246907
23行为型设计模式—备忘录模式https://blog.csdn.net/qq_39668819/article/details/116333844
24行为型设计模式—解释器模式https://blog.csdn.net/qq_39668819/article/details/116379466
中介者模式

在现实生活中,对象与对象之间常常存在着复杂的交互关系,如:公司中员工与员工之间的关系;世界上国家与国家之间的关系;以及草原中动物与动物之间的关系。这种关系一般呈 “网状结构”,每个对象都与多个对象交互,不利于管理,且一旦有修改就会牵连到多个对象,非常复杂。

如果我们在这个 “网状结构” 中引入一个管理对象之间的关系的 “中介者”,将 “网状结构” 改为 “星型结构”,将大大降低各个对象之间的耦合度,降低系统的复杂度且方便扩展。如公司的微信群/钉钉群,国际关系中的联合国等等;以下以国际关系为例介绍 “网状结构” 与 “星型结构”。

网状结构:

在这里插入图片描述

星型结构

20210426223818665

通过上面两幅图对比,我们发现 “星型结构” 比 “网状结构” 更加简单明了,更容易理解,且对象之间的耦合度更低,管理起来也更加方便。上面这种引入联合国作为 “中介者” 的思想就是中介者模式。

模式的定义

中介者模式(Mediator)也叫调停者模式,它定义一个中介对象来封装一系列的对象交互,中介者使得各对象不需要显式的互相引用,而使其耦合松散,而且可以独立的改变他们之间的交互;它是一种对象行为模式。

模式的优点如下:

  • 类之间各司其职,符合迪米特法则。
  • 降低了对象之间的耦合性,使得对象易于独立地被复用。
  • 将对象间的一对多关联转变为一对一的关联,使对象间的关系易于理解和维护,提高系统的灵活性,使得系统易于维护和扩展。
  • 可以将对象的行为和协作进行抽象,能够比较灵活的处理对象间的相互作用。

缺点:

  • 将对象间的依赖关系封装到了中介者中,当对象越来越多时,中介者也会越来越臃肿,会变得复杂且难以维护,一旦中介者出现问题或不可用,则会影响到所有对象之间的交互。
模式的结构

关键概念:

  • 同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。

中介者模式的主要角色如下:

  • 抽象中介者角色(Mediator):定义了同事对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
  • 具体中介者角色(Concrete Mediator):实现抽象中介者的方法,它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。”
  • 抽象同事类角色(Colleague):定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法。
  • 具体同事类角色(Concrete Colleague):每个具体同事只知道自己的行为,而不了解其他同事类的情况,但它们却都认识中介者对象,当需要与其他同事对象交互时,可以通过调度中介者对象来实现。

模式的 UML 类图如下:

在这里插入图片描述

模式的使用

下面以圆形属性计算为例,介绍中介者模式的使用。

在该实例中,圆共有三个属性类:半径、周长、面积;当其中任意一个属性类的值发生改变时,对应的其它两项属性都应发生改变;这时,这三个属性之间的交互关系就形成了网状结构。我们将这三个属性类之间的交互关系抽离出来形成一个用来管理其交互关系的中介者 “CircularCalculate”,单个属性类中只负责管理自身属性,对应改变其它属性的交互由中介者实现。

  • 抽象中介者:Mediator 定义了三个圆属性变化的方法;
  • 具体中介者:CircularCalculate 包含了三个具体同事对象,分别为 radiusperimeteracreage,同时实现了抽象中介者中三个圆属性变化的方法:
    • radiusChange:当圆的半径发生改变时,同步改变圆的周长和面积。
    • perimeterChange:当圆的周长发生改变时,同步改变圆的半径和面积。
    • acreageChange:当圆的面积发生改变时,同步改变圆的半径和周长。
  • 抽象同事类:包含一个圆的属性值,和一个改变属性值的抽象方法。
  • 具体同时类:实现了改变属性值的抽象方法,共有三个具体同事类,分别如下:
    • Radius:半径类,提供了一个改变半径的方法,包含一个半径参数和一个具体中介者参数,当半径发生改变时,同步调用中介者中的 radiusChange 方法同步改变 perimeteracreage
    • Perimeter:周长类,提供了一个改变周长的方法,包含一个周长参数和一个具体中介者参数,当周长发生改变时,同步调用中介者中的 perimeterChange 方法同步改变 radiusacreage
    • Acreage:面积类,提供了一个改变面积的方法,包含一个面积参数和一个具体中介者参数,当面积发生改变时,同步调用中介者中的 acreageChange 方法同步改变 radiusperimeter
/**
* 抽象中介者
*/
public interface Mediator {

    /**
     * 半径改变
     * @param radius
     */
    void radiusChange(BigDecimal radius);

    /**
     * 周长改变
     * @param perimeter
     */
    void perimeterChange(BigDecimal perimeter);

    /**
     * 面积改变
     * @param acreage
     */
    void acreageChange(BigDecimal acreage);
}

/**
* 具体中介者 - 圆属性计算
*/
public class CircularCalculate implements Mediator {

    final static BigInteger HUNDRED = BigInteger.valueOf(100);

    private BigDecimal pi = new BigDecimal(3.14).setScale(2, BigDecimal.ROUND_DOWN);

    private Radius radius;

    private Perimeter perimeter;

    private Acreage acreage;

    public CircularCalculate(Radius radius, Perimeter perimeter, Acreage acreage) {
        this.radius = radius;
        this.perimeter = perimeter;
        this.acreage = acreage;
    }

    @Override
    public void radiusChange(BigDecimal radius) {
        BigDecimal c = radius.multiply(new BigDecimal(2))
                             .multiply(pi)
                             .setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal area = radius.multiply(radius)
                                .multiply(pi)
                                .setScale(2, BigDecimal.ROUND_DOWN);
        perimeter.setNumber(c);
        acreage.setNumber(area);
    }

    @Override
    public void perimeterChange(BigDecimal perimeter) {
        BigDecimal r = perimeter.divide(new BigDecimal(2), 2, BigDecimal.ROUND_DOWN)
                               .divide(pi, 2, BigDecimal.ROUND_DOWN)
                               .setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal area = perimeter.divide(new BigDecimal(2), 2, BigDecimal.ROUND_DOWN)
                                  .multiply(r)
                                  .setScale(2, BigDecimal.ROUND_DOWN);
        radius.setNumber(r);
        acreage.setNumber(area);
    }

    @Override
    public void acreageChange(BigDecimal acreage) {
        BigDecimal square = acreage.divide(pi, 2, BigDecimal.ROUND_DOWN);
        BigDecimal r = sqrt(square, 2, BigDecimal.ROUND_DOWN);
        BigDecimal c = acreage.divide(r, 2, BigDecimal.ROUND_DOWN)
                               .multiply(new BigDecimal(2))
                               .setScale(2, BigDecimal.ROUND_DOWN);
        radius.setNumber(r);
        perimeter.setNumber(c);
    }

    /**
     * 开平方根
     *
     * @param number
     * @param scale
     * @param roundingMode
     * @return
     */
    public BigDecimal sqrt(BigDecimal number, int scale, int roundingMode) {
        if (number.compareTo(BigDecimal.ZERO) < 0)
            throw new ArithmeticException("sqrt with negative");
        BigInteger integer = number.toBigInteger();
        StringBuffer sb = new StringBuffer();
        String strInt = integer.toString();
        int lenInt = strInt.length();
        if (lenInt % 2 != 0) {
            strInt = '0' + strInt;
            lenInt++;
        }
        BigInteger res = BigInteger.ZERO;
        BigInteger rem = BigInteger.ZERO;
        for (int i = 0; i < lenInt / 2; i++) {
            res = res.multiply(BigInteger.TEN);
            rem = rem.multiply(HUNDRED);

            BigInteger temp = new BigInteger(strInt.substring(i * 2, i * 2 + 2));
            rem = rem.add(temp);

            BigInteger j = BigInteger.TEN;
            while (j.compareTo(BigInteger.ZERO) > 0) {
                j = j.subtract(BigInteger.ONE);
                if (((res.add(j)).multiply(j)).compareTo(rem) <= 0) {
                    break;
                }
            }

            res = res.add(j);
            rem = rem.subtract(res.multiply(j));
            res = res.add(j);
            sb.append(j);
        }
        sb.append('.');
        BigDecimal fraction = number.subtract(number.setScale(0, BigDecimal.ROUND_DOWN));
        int fracLen = (fraction.scale() + 1) / 2;
        fraction = fraction.movePointRight(fracLen * 2);
        String strFrac = fraction.toPlainString();
        for (int i = 0; i <= scale; i++) {
            res = res.multiply(BigInteger.TEN);
            rem = rem.multiply(HUNDRED);

            if (i < fracLen) {
                BigInteger temp = new BigInteger(strFrac.substring(i * 2, i * 2 + 2));
                rem = rem.add(temp);
            }

            BigInteger j = BigInteger.TEN;
            while (j.compareTo(BigInteger.ZERO) > 0) {
                j = j.subtract(BigInteger.ONE);
                if (((res.add(j)).multiply(j)).compareTo(rem) <= 0) {
                    break;
                }
            }
            res = res.add(j);
            rem = rem.subtract(res.multiply(j));
            res = res.add(j);
            sb.append(j);
        }
        return new BigDecimal(sb.toString()).setScale(scale, roundingMode);
    }

}
/**
* 抽象同事类
*/
public abstract class Colleague {

    /**
     * 具体值
     */
    protected BigDecimal number;

    public Colleague(BigDecimal number) {
        this.number = number;
    }

    public BigDecimal getNumber() {
        return number;
    }

    public void setNumber(BigDecimal number) {
        this.number = number;
    }

    /**
     * 值改变
     * @param number
     * @param graphics
     */
    public abstract void changNumber(BigDecimal number, Mediator graphics);
}

/**
* 具体同事类 - 半径
*/
public class Radius extends Colleague{

    public Radius(BigDecimal number) {
        super(number);
    }

    @Override
    public void changNumber(BigDecimal number, Mediator graphics) {
        this.number = number;
        graphics.radiusChange(number);
    }
}

/**
* 具体同事类 - 周长
*/
public class Perimeter extends Colleague{

    public Perimeter(BigDecimal number) {
        super(number);
    }

    @Override
    public void changNumber(BigDecimal number, Mediator graphics) {
        this.number = number;
        graphics.perimeterChange(number);
    }
}

/**
* 具体同事类 - 面积
*/
public class Acreage extends Colleague{

    public Acreage(BigDecimal number) {
        super(number);
    }

    @Override
    public void changNumber(BigDecimal number, Mediator graphics) {
        this.number = number;
        graphics.acreageChange(number);
    }
}

/**
* 中介者模式测试类
*/
public class MediatorTest {

    private static BigDecimal pi = new BigDecimal(3.14);

    public static void main(String[] args) {
        BigDecimal r = new BigDecimal(5);
        BigDecimal c = r.multiply(new BigDecimal(2)).multiply(pi).setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal area = r.multiply(r).multiply(pi).setScale(2, BigDecimal.ROUND_DOWN);

        Radius radius = new Radius(r);
        Perimeter perimeter = new Perimeter(c);
        Acreage acreage = new Acreage(area);
        System.out.println("初始圆的数据=====>");
        System.out.println("半径:" + radius.getNumber() + " 周长:" + perimeter.getNumber() + " 面积:" + acreage.getNumber());
        System.out.println();

        CircularCalculate cc = new CircularCalculate(radius, perimeter, acreage);
        radius.changNumber(new BigDecimal(6), cc);
        System.out.println("半径修改为 " + radius.getNumber() + " 后圆的数据=====>");
        System.out.println("半径:" + radius.getNumber() + " 周长:" + perimeter.getNumber() + " 面积:" + acreage.getNumber());
        System.out.println();

        perimeter.changNumber(new BigDecimal(25.5), cc);
        System.out.println("周长修改为 " + perimeter.getNumber() + " 后圆的数据=====>");
        System.out.println("半径:" + radius.getNumber() + " 周长:" + perimeter.getNumber() + " 面积:" + acreage.getNumber());
        System.out.println();

        acreage.changNumber(new BigDecimal(500), cc);
        System.out.println("面积修改为 " + acreage.getNumber() + " 后圆的数据=====>");
        System.out.println("半径:" + radius.getNumber() + " 周长:" + perimeter.getNumber() + " 面积:" + acreage.getNumber());
        System.out.println();

    }
}

运行程序,结果如下:

在这里插入图片描述

模式的应用场景

中介者模式是一种比较常用的模式,也是一种比较容易被滥用的模式。适当的使用中介者模式可以使原本凌乱的对象关系变得清晰,但是如果滥用,则可能会带来反的效果。一般来说,只有对于那种同事类之间是网状结构的关系,才会考虑使用中介者模式。大多数的情况,同事类之间的关系不会复杂到混乱不堪的网状结构,因此,大多数情况下,将对象间的依赖关系封装的同事类内部就可以的,没有必要非引入中介者模式。滥用中介者模式,只会让事情变的更复杂。

中介者模式的主要运用场景如下:

  • 中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合。
  • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
  • 定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值