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,保证了最大值是 数组的长度减一, 如此往复

猜你喜欢

转载自www.cnblogs.com/ZhuChangwu/p/11237899.html