使用一些映射根据输入对象创建新的对象实例

时间:2019-02-26 22:58:14

标签: typescript

让我们假设我们有Commands和CommandHandlers。每个命令一个CommandHandler。

现在,我想根据某些映射按Command对象获取CommandHandler对象的新实例。定义此类地图的最佳方法是什么? 解决方案应在代码最小化后起作用,并且应该易于重构。

目前我有我个人不喜欢的这种解决方案。

interface Command {}
class ConcreteCommand implements Command {}
class ConcreteCommand2 implements Command {}

interface CommandHandler {}
class ConcreteCommandHandler implements CommandHandler {}
class ConcreteCommand2Handler implements CommandHandler {}

const map = [ //I don't like this kind of map, any other ways?
    [ConcreteCommand, ConcreteCommandHandler],
    [ConcreteCommand2, ConcreteCommand2Handler]
];

function getCommandHandler(command: Command): CommandHandler {
    for(let pair of map) {
        if (command instanceof pair[0]) {
            return new pair[1];
        }
    }
    throw new Error('Unable to find CommandHandler.');
}

console.log( getCommandHandler(new ConcreteCommand()) ); //ConcreteCommandHandler

This code at TypeScript Playground.

3 个答案:

答案 0 :(得分:0)

JavaScript的数据类型称为Map。来自MDN

  

Map对象包含键值对,并记住键的原始插入顺序。任何值(对象值和原始值)都可以用作键或值。

要使用一个:

const map = new Map()

map.set(ConcreteCommand, ConcreteCommandHandler)

const handler = new (map.get(ConcreteCommand))()

警告是您的代码无法与此配合使用,因为:

getCommandHandler(new ConcreteCommand())

每个实例将被视为唯一键。不过,您可以使用该函数本身:map.set(ConcreteCommand)

答案 1 :(得分:0)

本地Maps对此非常有用:

const map = new Map<Command, CommandHandler>([
    [ConcreteCommand, ConcreteCommandHandler],
    [ConcreteCommand2, ConcreteCommand2Handler]
])

function getCommandHandler(command: Command): CommandHandler
{
    if (map.has(command) == false)
        throw new Error('Unable to find CommandHandler.');

    return map.get(command);
}

答案 2 :(得分:0)

如果需要类型,请使用它,但是有问题

interface Cmd<T = string> { _T: T  }
interface CmdHandler<T = string> { _T: T }

declare class CmdOne implements Cmd<'CmdOne'> { _T: 'CmdOne' }
declare class CmdTwo implements Cmd<'CmdTwo'> { _T: 'CmdTwo' }
declare class CmdThree implements Cmd<'CmdThree'> { _T: 'CmdThree' }

declare class CmdHandlerOne implements CmdHandler<'CmdOne'> { _T: 'CmdOne' }
declare class CmdHandlerTwo implements CmdHandler<'CmdTwo'> { _T: 'CmdTwo' }
//declare class CmdHandlerThree implements CmdHandler<'CmdThree'> { _T: 'CmdThree' }

const cmds = [
    [CmdOne, CmdHandlerOne],
    [CmdTwo, CmdHandlerTwo],
    //[CmdThree, CmdHandlerThree],
];

export function CmdFactory<T>(cmd: Cmd<T>): CmdHandler<T> {
    const handle = cmds.find(pair => cmd instanceof pair[0])[1];
    return new handle as any; /// not good!
}

CmdFactory(new CmdOne)
CmdFactory(new CmdThree) /// Need error

playground