javascript - 装饰一个类实例而不显式转发所有函数

时间:2017-07-26 11:23:12

标签: javascript

首先让我说这更像是一个好奇心问题,因为正如您将看到的那样,我能够实现所需的功能。
但是,鉴于javascript是一种超级灵活的语言,我想看看其他开发者可能会想到这个问题:

我有一个从供应商函数返回的类的实例:

const connection = vendorDatabaseLib.createConnection();

现在,我想创建一个装饰器,它将为连接类添加功能,例如,重新连接逻辑。
让我们称之为PersistentConnection。除了我添加的自定义函数之外,我希望PersistentConnection的实例将所有函数调用转发到原始Connection实例。并且在某些功能中覆盖了行为 我当然可以显式地实现所有Connection的函数并将它们转发给内部对象,但可能有很多这些函数,所以我很快就放弃了这个想法。

以下是我对如何实现这一目标的看法:

  1. 猴子修补,我可以创建一个继承自供应商PersistentConnection的{​​{1}}类,然后修补供应商Connection函数以返回vendorDatabaseLib.createConnection而不是装饰器。我希望增加的功能。很诱人,但很糟糕。
  2. 创建一个装饰器,它遍历PersistentConnection个函数并动态创建转发,例如:
  3. Connection

    1. class PersistentConnection{ constructor(connection){ this._connection = connection; // Iterate through all functions for (prop in this._connection){ if(typeof(this._connection[prop]) === 'function'){ // Create functions dynamically for each forward this[prop] = (...args) => { this._connection[prop](...args); } } } } // This is the added logic reconnect(){ // Custom logic } } 实例设置为Connection实例的原型:
    2. PersistentConnection

      这是我能想到的最“自动”的方式..但它只是非常难看,每次创建实例时都需要声明自定义函数。

      我仍然觉得我错过了一些东西,比如Ruby的神奇function persistenChannel(channel){ const persistentChannel = {}; Object.setPrototypeOf(persistentChannel, channel); persistentChannel.reconnect = () => { // custom logic } }(或pythons method_missing)函数,它在抛出__getattr__异常之前被调用,并让你定义“安全网”逻辑(如委托对内部method is missing对象的所有调用 有没有更好的方法来实现此功能? 非常感谢[=

1 个答案:

答案 0 :(得分:1)

让我们从我们拥有的东西开始。在任何情况下,大部分功能都将由供应商对象执行。我们不知道细节实现所以我们不能依赖这个对象没有状态。这意味着,在任何情况下,我们都需要新的persistentConnection的 new 连接对象。这可以通过proxy object

来实现

让我们尝试这样做:

function Connection() {
    this.connect = () => console.log('connected by Connection class');
    this.disconnect = () => console.log('disconnected by Connection class');
}


function persistantConnectionFactory() {
    function PersistentConnection() {
        this.checkConnection = () => console.log('no connection');
    }
    const instance = new PersistentConnection();
    const proxy = new Proxy(instance, {
        get: function (target, name) {
            if (!(name in target)) {
                console.log('adding new prototype')
                Object.setPrototypeOf(instance, new Connection())
            }

            return target[name];
        }
    });

    return proxy;
}

var c = persistantConnectionFactory();
c.checkConnection();
c.connect();

这个解决方案好吗?我想不是。没有很好的理由,这会增加复杂性而没有任何价值原型应该足够了。