• Netty中的策略者模式


    策略者模式的特点

    在设计类的继承体系时,我们会刻意的把公共的部分都提取到基类中

    比如先设计Person类,把人类都具有的行为放到这个Person,特有的行为设计成抽象方法,让子类具体去实现, 这样后续无论我们再去构造学生,还是构造老师,大家都继承Person,就达到了代码复用的目的

    但是这样问题就来了,对老师类来说,需要有教学的行为,假如这个方法以抽象方法的形式放在基类,那么对于继承了Person的学生类来说就不对了,因为没有要求学生一定会教学,但是现在学生就得实现这个方法

    如果我们把老师的教学的行为作为 老师类的私有, 这时候,小明教小李学习, 就意味着对小明来说,他需要教学的行为, 前前后后看起来就开始矛盾了, 到底怎么处理呢?

    策略者模式,就解决了这个问题, 它把行为抽象成了接口,以接口+实现的方式,解决上面的问题, 就上面的例子来说,可以把教学设计成接口,任何类,只要实现了这个接口,就可以教学,而不一定强制要求只有老师才可以实现它

    总的来说,策略模式,就是将行为抽象成接口+实现的模式

    Netty中策略者模式的使用

    netty的bossgroup中接收到了新的连接之后会使用选择器Chooser,从WorkerGroup中选择出一个EventLoop, 然后把这个连接注册进选出的 EventLoop

    netty的选择器,使用的就是策略者模式,将选择的行为 设计成接口,不同的选择器根据自己不同的需求用不用的方式实现选择器接口

    行为接口

    @UnstableApi
    public interface EventExecutorChooserFactory {
    
    EventExecutorChooser newChooser(EventExecutor[] executors);
    @UnstableApi
    interface EventExecutorChooser {
        EventExecutor next();
    }
    }
    
    

    选择器不同的实现:

    if (isPowerOfTwo(executors.length)) {// todo 如果是2的指数倍, 返回PowerOfTwoEventExecutorChooser
        return new PowerOfTwoEventExecutorChooser(executors);
    } else {// todo  否则返回同样的实例
        return new GenericEventExecutorChooser(executors);
    }
    

    根据线程执行器的数量确定使用那种具体的行为

    行为1:PowerOfTwoEventExecutorChooser

    private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;
        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }
    
        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    

    主要看它的executors[idx.getAndIncrement() & executors.length - 1]

    进行速度更快的与运算

    1 & 1 = 1
    1 & 0 = 0
    0 & 1 = 0
    

    当数组的长度是2的幂次方时, 用二进制表示就是1111... 全是1, 再减去1 ,就是0111...

    无论前面的数是谁,对一个 0111... 进行与运算,得到的结果就是从0-0111...大小的数, 循环往复

    行为2:GenericEventExecutorChooser

    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;
    
    GenericEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }
    
    @Override
    public EventExecutor next() {
        // todo 从0开始到最后一个, 再从零开始,到最后一个
        return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }
    

    主要的一步就是Math.abs(idx.getAndIncrement() % executors.length)
    可以看到,从0开始一直往后对数组的长度取余数,小数对大数取余数=小数, 保证了数组的下标从0开始递增, 自己对自己取余数=0,保证了最大值是 数组的长度减一, 如此往复

  • 相关阅读:
    Python之迭代器,生成器
    Python函数--装饰器进阶
    Python之函数的本质、闭包、装饰器
    Python之函数--命名空间、作用域、global、nonlocal、函数的嵌套和作用域链
    Python函数的定义与调用、返回值、参数
    Python之文件操作
    Python之集合
    基本数据类型补充,深浅copy
    Python基础-元组、列表、字典
    Python常用模块(一)
  • 原文地址:https://www.cnblogs.com/ZhuChangwu/p/11237899.html
Copyright © 2020-2023  润新知