Typescript命令模式返回类型
下面是命令模式,其中有一个命令和一个命令处理程序,它们被添加到Typescript命令模式返回类型,typescript,command-pattern,Typescript,Command Pattern,下面是命令模式,其中有一个命令和一个命令处理程序,它们被添加到CommandBus中,然后在调用时在那里执行。在本例中,命令有一个类型,我希望在CommandBus中执行命令时返回该类型 问题是最后一行var whatisset=CommandBus.execute(新的GetStringCommand(“Hello,world”)更具体地说,我想删除该语句,因为它应该来自命令。CommandBus类应该知道它应该从类GetStringCommand implements命令返回 接口命令{ 名
CommandBus
中,然后在调用时在那里执行。在本例中,命令有一个类型
,我希望在CommandBus
中执行命令时返回该类型
问题是最后一行var whatisset=CommandBus.execute(新的GetStringCommand(“Hello,world”)
更具体地说,我想删除该语句,因为它应该来自命令
。CommandBus
类应该知道它应该从类GetStringCommand implements命令返回
接口命令{
名称:字符串;
}
类GetStringCommand实现该命令{
公共str:string;
公共名称:string=“GetStringCommand”;
构造函数(str:string){
this.str=str;
}
}
接口命令处理程序{
执行(命令:命令):T;
}
类GetStringHandler实现CommandHandler{
执行(命令:GetStringCommand):字符串{
return命令.str;
}
}
接口命令注册表{
[x:string]:CommandHandler
}
类命令总线{
私有静态操作:CommandRegistry={};
静态添加(名称:字符串,命令:CommandHandler){
CommandBus.actions[name]=命令;
}
静态执行(命令:命令):T{
返回CommandBus.actions[command.name].execute(command);
}
}
add(“GetStringCommand”,新的GetStringHandler());
var whatIsThis=CommandBus.execute(新的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);
}
}
导出类SaveSchemaCommandHandler实现CommandHandlerBase{
执行(命令:SaveSchemaCommand){
var db=MongoConnection.db;
var collectionOptions={autoIndexID:true};
createCollection(command.schema.getName(),collectionOptions);
}
}
据我所知,您的处理程序是真正的命令,而您所调用的命令只是处理程序执行所需的参数
您可以用简单的界面替换您的“命令”,您的处理程序将成为命令。
然后,您就可以消除这些新命令对类的需求,因为您可以将execute函数作为命令传递
大概是这样的:
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" } });
(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" });
此选项不太可扩展,但它仍然是一个选项。为什么需要处理程序?您不能在命令
?分离关注点中执行吗。其思想是,一个命令可以被多个命令处理程序使用,例如,对于一个保存操作,您有多个数据库系统,这些数据库将分别有一个命令处理程序来执行该操作(实际上它们将成为即插即用),您不需要为所有数据库编写一个巨大的命令,而且,如果您想自定义要使用的数据库,那么。。如果你有不同的数据库,那么你需要不同的命令来使用它们。除非我在您的设计中遗漏了什么,否则处理程序似乎只是返回值的命令的包装器。也许您可以在代码中包含一个更有趣的示例?请参见上面的示例,我认为用接口替换命令是一个好主意,因为它们只包含结构,但是上面的返回类型有一个问题:var xyz:string=CommandBus.execute(“GetStringCommand”,{value:“my string”})
会给出错误“Type'{}'不可分配给Type'string'”,您可以在前面传入,但我想避免这种情况。我认为这个解决方案已经足够好了,函数必须是类,因为它们包含的类多于正常执行的类,谢谢您的帮助!检查我修改过的答案,我给了你3个选项来处理这个问题。@NitzanTomer在你的第一个例子中,当执行命令时,我会传入GetStringCommandData
,而不是基本的CommandData
。但是泛型的返回类型推断似乎丢失了,变成了{}
。有没有一种方法可以避免在GetStringCommandData
中包含泛型
class CommandBus {
...
static execute(name: string, data: CommandData): any {
return CommandBus.actions[name](data);
}
}
let str: string = CommandBus.execute("GetStringCommand", { value: "my string" });
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" });