Eventbus

EventBus 设计分享#

回顾原理#

无论事件总线支持怎样的拓展功能,内部实现怎样优雅,其设计基本上还是基于发布-订阅模型。

该模型总是包含用于存贮消息映射到回调的数据集合,事件的分发方法,事件的订阅和取消订阅方法。(以下的事件总线,事件系统,事件中心皆指该模型的实际实现)

发布订阅模型可以轻松支持事件广播,即单一的消息发布者可以把消息传递给多个关心其发送的消息的听众,这些听众会在监听到自己关心的消息时做出相对应的反应。

在类的依赖关系中,听众和消息发布者都无需关心对方,他们共同依赖事件模块而不是相互耦合。优点是利于代码的维护,复用。这也遵循了迪米特法则。 下面举一个例子来对比接入事件总线前后类的依赖关系

public class VTuber
{
    private readonly List<Fans> fansList;

    public VTuber(List<Fans> fansList)
    {
        this.fansList = fansList;
    }

    public void Sing()
    {
        fansList.ForEach(fans => fans.OnVTuberSing());
    }
}

public class Fans
{
    public readonly Action OnVTuberSing;

    protected Fans(Action onVTuberSing)
    {
        OnVTuberSing = onVTuberSing;
    }
}

上面的代码描述了在 VTuber 唱歌后 Fans 表态的场景。VTuber 不得不了解其所有的粉丝,并在唱歌后逐一通知他们。然而,VTuber 和 Fans 紧密耦合在了一起,只要有一个缺失或者发生更改,代码就无法通过编译或必须紧跟着更新另一个类。

当不止粉丝来关心 VTuber 的时候,事情就变得更加复杂了。VTuber 必须了解关注 ta 的所有人:粉丝、网警、平台、乐子人,以便在自己有所举动时他们能发出正常的反馈——这很可笑不是吗?哪怕以显示的眼光去看,依赖关系也完全倒置了。事实上是后者关心前者,前者往往完全不了解后者,甚至不清楚后者的存在。 或许熟悉抽象的你已经有了相对应的优化思路,但不要着急,我们再来看看事件总线介入后的局面。

Creational Patterns

本文为 2024 年寒假 SAST 游戏组 WOC 授课资料留档

抽象了实例化过程。

  • 接口,抽象类
  • new()

工厂方法 Factory Method#

工厂方法的意图#

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

具体实现#

如果不用工厂方法,我们如何实现?

public class Wand//产品
{
    public string Name { get; set; }
}

public class FireWand : Wand
{
    public FireWand()
    {
        Name = "Fire Wand";
    }
}

public class IceWand : Wand
{
    public IceWand()
    {
        Name = "Ice Wand";
    }
}

int main()//实例化,客户端,调用者
{
    var fireWand = new FireWand();
    var iceWand = new IceWand();
}

如果我们需要一个新的魔杖,我们需要实现一个新的魔杖类,然后实现一个新的方法,这样就会导致类的爆炸。