Typescript 命令模式 return 类型
Typescript Command pattern return type
下面是命令模式,您有一个命令和一个命令的处理程序,它们被添加到 CommandBus
,然后在被调用时在那里执行。在这种情况下,该命令具有一种类型 <string>
,我希望在 CommandBus
中执行命令时对其进行 returned
问题是最后一行 var whatIsThis = CommandBus.execute<string>(new GetStringCommand("Hello, world"));
更具体地说,我想从该语句中删除,因为它应该来自 Command
。 CommandBus
class 应该从 class GetStringCommand implements Command<string>
知道它应该 return。
interface Command<T> {
name:string;
}
class GetStringCommand implements Command<string> {
public str:string;
public name:string = "GetStringCommand";
constructor(str:string){
this.str = str;
}
}
interface CommandHandler<T> {
execute(command:Command<T>): T;
}
class GetStringHandler implements CommandHandler<string> {
execute(command:GetStringCommand):string {
return command.str;
}
}
interface CommandRegistry {
[x:string]: CommandHandler<any>
}
class CommandBus {
private static actions:CommandRegistry = {};
static add(name:string, command:CommandHandler<any>) {
CommandBus.actions[name] = command;
}
static execute<T>(command:Command<T>) : T {
return CommandBus.actions[command.name].execute(command);
}
}
CommandBus.add("GetStringCommand", new GetStringHandler());
var whatIsThis = CommandBus.execute<string>(new GetStringCommand("Hello, world"));
上面的解决方案是有效的并且运行良好,但它是一个糟糕的解决方案,因为它使重构变得痛苦,并且让我不得不一遍又一遍地重复自己,因为我将使用数千个命令。
实例
这是在 MongoDB 中保存模式的命令处理程序的示例,可以使用相同的命令在 MySQL
中创建模式
export class SaveSchemaCommandHandler implements CommandHandlerBase<void> {
execute(command:SaveSchemaCommand) {
var db = MongoConnection.db;
var collectionOptions = { autoIndexID: true };
db.createCollection(command.schema.getName(), collectionOptions);
}
}
据我了解,您的处理程序是真正的命令,而您所谓的命令只是处理程序执行所需的参数。
您可以用简单的界面替换您的 "commands",并且您的处理程序成为命令。
然后,您可以删除这些新命令对 类 的需要,因为您可以将执行函数作为命令传递。
像这样:
interface CommandData {}
interface GetStringCommandData extends CommandData {
value: string;
}
interface SaveSchemaCommandData extends CommandData {
schema: { name: string };
}
type Command<In extends CommandData, Out> = (data: In) => Out;
interface CommandRegistry {
[x: string]: Command<CommandData, any>;
}
class CommandBus {
private static actions:CommandRegistry = {};
static add(name: string, command: Command<CommandData, any>) {
CommandBus.actions[name] = command;
}
static execute<T>(name: string, data: CommandData) : T {
return CommandBus.actions[name](data);
}
}
CommandBus.add("GetStringCommand", (data: GetStringCommandData) => data.value);
CommandBus.add("SaveSchemaCommand", (data: SaveSchemaCommandData) => {
let db = MongoConnection.db;
let collectionOptions = { autoIndexID: true };
db.createCollection(data.schema.name, collectionOptions);
});
CommandBus.execute("GetStringCommand", { value: "my string" });
CommandBus.execute("SaveSchemaCommand", { schema: { name: "mySchema" } });
看起来更简单,更容易维护,但我不确定它是否符合您的所有需求。
编辑
从执行操作中获取正确的类型并非易事,但您有几个选择:
(1) 在 CommandData
中使用 return 类型泛型:
interface CommandData<T> {}
interface GetStringCommandData extends CommandData<string> {
value: string;
}
class CommandBus {
...
static execute<T>(name: string, data: CommandData<T>): T {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" } as CommandData<string>);
(2) 使用 any
:
class CommandBus {
...
static execute(name: string, data: CommandData): any {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" });
(3) 声明执行的可能签名:
class CommandBus {
...
static execute(name: "GetStringCommand", data: GetStringCommandData): string;
static execute(name: "SaveSchemaCommand", data: SaveSchemaCommandData): void;
static execute(name: string, data: CommandData): any;
static execute(name: string, data: CommandData): any {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" });
这个选项的可扩展性不是很好,但它仍然是一个选项。
下面是命令模式,您有一个命令和一个命令的处理程序,它们被添加到 CommandBus
,然后在被调用时在那里执行。在这种情况下,该命令具有一种类型 <string>
,我希望在 CommandBus
问题是最后一行 var whatIsThis = CommandBus.execute<string>(new GetStringCommand("Hello, world"));
更具体地说,我想从该语句中删除,因为它应该来自 Command
。 CommandBus
class 应该从 class GetStringCommand implements Command<string>
知道它应该 return。
interface Command<T> {
name:string;
}
class GetStringCommand implements Command<string> {
public str:string;
public name:string = "GetStringCommand";
constructor(str:string){
this.str = str;
}
}
interface CommandHandler<T> {
execute(command:Command<T>): T;
}
class GetStringHandler implements CommandHandler<string> {
execute(command:GetStringCommand):string {
return command.str;
}
}
interface CommandRegistry {
[x:string]: CommandHandler<any>
}
class CommandBus {
private static actions:CommandRegistry = {};
static add(name:string, command:CommandHandler<any>) {
CommandBus.actions[name] = command;
}
static execute<T>(command:Command<T>) : T {
return CommandBus.actions[command.name].execute(command);
}
}
CommandBus.add("GetStringCommand", new GetStringHandler());
var whatIsThis = CommandBus.execute<string>(new GetStringCommand("Hello, world"));
上面的解决方案是有效的并且运行良好,但它是一个糟糕的解决方案,因为它使重构变得痛苦,并且让我不得不一遍又一遍地重复自己,因为我将使用数千个命令。
实例 这是在 MongoDB 中保存模式的命令处理程序的示例,可以使用相同的命令在 MySQL
中创建模式export class SaveSchemaCommandHandler implements CommandHandlerBase<void> {
execute(command:SaveSchemaCommand) {
var db = MongoConnection.db;
var collectionOptions = { autoIndexID: true };
db.createCollection(command.schema.getName(), collectionOptions);
}
}
据我了解,您的处理程序是真正的命令,而您所谓的命令只是处理程序执行所需的参数。
您可以用简单的界面替换您的 "commands",并且您的处理程序成为命令。
然后,您可以删除这些新命令对 类 的需要,因为您可以将执行函数作为命令传递。
像这样:
interface CommandData {}
interface GetStringCommandData extends CommandData {
value: string;
}
interface SaveSchemaCommandData extends CommandData {
schema: { name: string };
}
type Command<In extends CommandData, Out> = (data: In) => Out;
interface CommandRegistry {
[x: string]: Command<CommandData, any>;
}
class CommandBus {
private static actions:CommandRegistry = {};
static add(name: string, command: Command<CommandData, any>) {
CommandBus.actions[name] = command;
}
static execute<T>(name: string, data: CommandData) : T {
return CommandBus.actions[name](data);
}
}
CommandBus.add("GetStringCommand", (data: GetStringCommandData) => data.value);
CommandBus.add("SaveSchemaCommand", (data: SaveSchemaCommandData) => {
let db = MongoConnection.db;
let collectionOptions = { autoIndexID: true };
db.createCollection(data.schema.name, collectionOptions);
});
CommandBus.execute("GetStringCommand", { value: "my string" });
CommandBus.execute("SaveSchemaCommand", { schema: { name: "mySchema" } });
看起来更简单,更容易维护,但我不确定它是否符合您的所有需求。
编辑
从执行操作中获取正确的类型并非易事,但您有几个选择:
(1) 在 CommandData
中使用 return 类型泛型:
interface CommandData<T> {}
interface GetStringCommandData extends CommandData<string> {
value: string;
}
class CommandBus {
...
static execute<T>(name: string, data: CommandData<T>): T {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" } as CommandData<string>);
(2) 使用 any
:
class CommandBus {
...
static execute(name: string, data: CommandData): any {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" });
(3) 声明执行的可能签名:
class CommandBus {
...
static execute(name: "GetStringCommand", data: GetStringCommandData): string;
static execute(name: "SaveSchemaCommand", data: SaveSchemaCommandData): void;
static execute(name: string, data: CommandData): any;
static execute(name: string, data: CommandData): any {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" });
这个选项的可扩展性不是很好,但它仍然是一个选项。