Класс TypeScript с методом, не используемым в каждом экземпляре - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть класс TypeScript, который создает основы связи по шине ZMQ. Сначала я хотел создать общий класс, который я могу создавать столько раз, сколько потребуется. Но теперь мне нужно сделать больше экземпляров, которые не полностью соответствуют общему классу, который я сделал. На самом деле единственное отличие состоит в том, что в этих новых случаях метод request никогда не используется в зависимости от type. Итак, возможно ли как-то сохранить тот же общий класс, но игнорировать метод request, когда он не требуется?

let zmq = require("zeromq")

class ZMQBus {
    socket:any
    port:number

    constructor(type:string, port:number) {
        this.socket = zmq.socket(type)
        this.port   = port
    }

    open(): void {
        this.socket.connect("tcp://localhost:" + this.port)

        this.socket.on("message", function(reply) {
            console.log("Received reply : " + reply.toString());
        })
    }

    request(msg:any): void {
        this.socket.send(msg);
    }

    close(): void {
        this.socket.close();
    }
}

1 Ответ

0 голосов
/ 12 февраля 2020

Я знаю, что вы сказали, что хотели бы избежать двух занятий, потому что не хотели подразумевать, что они разные. Запрос, который в некоторых случаях не имеет значения, не делает его вредным. Вы все еще можете использовать один класс с единственной реализацией request, которую вы используете только тогда, когда это требуется. Если вам действительно нужно указать, что request отсутствует, вам придется создать отдельный тип. Вы можете достичь семантически того, что вы хотите, без каких-либо антипаттернов, используя фабричный шаблон и условные типы

type ZmqTypes = "REQUEST" | "NOREQUEST";

interface ZMQBus {
  open: () => void;
  close: () => void;
  request?: (msg: any) => void;
  type: ZmqTypes;
  port: number;
}

interface ZMQBusR extends ZMQBus {
  request: (msg: any) => void;
}

interface ZMQBusNoR extends Omit<ZMQBus, "request"> {}

class GenericZMQBus implements ZMQBus {
    socket:any
    port:number

    constructor(type:string, port:number) {
        this.socket = zmq.socket(type)
        this.port   = port
    }

    open(): void {
        this.socket.connect("tcp://localhost:" + this.port)

        this.socket.on("message", function(reply : any) {
            console.log("Received reply : " + reply.toString());
        })
    }

    close(): void {
        this.socket.close();
    }
}

class ZMQBusWithRequest extends GenericZMQBus implements ZMQBusR {
  request(msg : any) {
    console.log(msg);
  }
}

function createZMQBus<T extends ZmqTypes>(type: T, port: number) : T extends "REQUEST" ? ZMQBusR : ZMQBusNoR {
  if (type === "REQUEST") { 
    return new ZMQBusWithRequest(type, port) as unknown as T extends "REQUEST" ? ZMQBusR : ZMQBusNoR;
  }
  return new GenericZMQBus(type, port) as unknown as T extends "REQUEST" ? ZMQBusR : ZMQBusNoR;
}

const zmqObj = createZMQBus("REQUEST", 999);
const zmqObj1 = createZMQBus("NOREQUEST", 999);

zmqObj.request('hello');
zmqObj1.request('error'); // is an error

У вас все еще есть несколько классов и интерфейсов со строгой системой типов, но единственный способ создать те объекты, которые подразумевает последовательную цель, если не последовательную реализацию. И поскольку оба расширяют один универсальный интерфейс c, вы можете передавать любой тип как один ZMQType. Вам просто нужно убедиться, что вы проверяете правильность наличия метода request, прежде чем пытаться его использовать.

function testZMQImplementation(z: ZMQBus) {
  if (z.request) {
    z.request('testing')
  }
}

testZMQImplementation(zmqObj);
testZMQImplementation(zmqObj1);
...