dongxiusuo9881 2016-09-03 20:26
浏览 37
已采纳

如何通过Golang的组合继承将Command调度到正确的Command Handler?

I want to learn to program in Go, I decided as a pet program I would do a simple dispatcher of different Commands to several CommandHandler (if the CommandHandler has the same name as the Command it should handle.)

My problem is when I want to have a CommandHandlerManager that publishes a Commands that would be dispatch to the correct CommandHandler, it tells me that I need to have a concrete implementation of my HelloWorldCommand because HelloWorldCommandHandler doesn't implement the interface of Command.

Error message at compilation

E:\Desktop\ManBear\golang\src>go run main.go
# command-line-arguments
.\main.go:71: cannot use cmdHandler (type HelloWorldCommandHandler) as type CommandHandler in array or slice literal:
        HelloWorldCommandHandler does not implement CommandHandler (wrong type for Handle method)
                have Handle(HelloWorldCommand)
                want Handle(Command)

I would need that someone explains the me what I'm doing wrong, I guessed it meant that I should implement an alone func method to my HelloWorldCommandHandler for the interface alone like below:

func (ch HelloWorldCommandHandler) Handle(cmd Command) {
    fmt.Println("HelloWorldCommandHandler handled the basic command with name --> " + cmd.GetName())
}

But it created more type-related errors.

A working example of what I'm trying to do with an explanation of how and why I'm doing it wrong would be appreciated.

Thank you.

Here's my code:

package main 

import (
    "fmt"
    "strconv"
)


type Command interface {
    GetName() string
}


type CommandHandler interface {
    Command
    Handle(cmd Command)
}


type HelloWorldCommand struct {
    Command
    Name string
    Age int
}

func (cmd HelloWorldCommand) GetName() string {
    return "HelloWorldCommand"
}


type HelloWorldCommandHandler struct {
    CommandHandler
}

func (cmd HelloWorldCommandHandler) GetName() string {
    return "HelloWorldCommand"
}

func (ch HelloWorldCommandHandler) Handle(cmd HelloWorldCommand) {
    fmt.Println("Hello World! My name is " + cmd.Name + " and I'm " + strconv.Itoa(cmd.Age) + " years old!")
}

type CommandHandlerManager struct {
    CommandHandlers []CommandHandler
}

func (chm CommandHandlerManager) Publish(cmd Command) {

    for _, cmdHandler := range chm.CommandHandlers {
        if cmd.GetName() == cmdHandler.GetName() {
            cmdHandler.Handle(cmd)
        }
    }
}


func main() {

    fmt.Println("Hey my friend!")

    cmd := HelloWorldCommand {Name: "ManBear", Age: 357}
    cmdHandler := HelloWorldCommandHandler {}

    fmt.Println(cmd.GetName())
    fmt.Println(cmdHandler.GetName())

    cmdHandler.Handle(cmd)

    cmdHandlerManager := CommandHandlerManager { 
        CommandHandlers: []CommandHandler { 
            cmdHandler, // <-- the error is here 
        },
    };
}

UPDATE:

For the curious, here is a functionning version of my pet program

Thanks to the help of Dean Elbaz by suggesting to use the type assertion, it makes it possible to handle a Command by it correct CommandHandler and use the correct set of values that comes with each Command.

package main

import (
    "fmt"
    "strconv"
    "time"
)


type Command interface {
    GetName() string
}


type CommandHandler interface {
    Command
    Handle(cmd Command)
}

const HelloWorldCommandName string = "HelloWorldCommand"

type HelloWorldCommand struct {
    Command
    Name string
    Age int
}

func (cmd HelloWorldCommand) GetName() string {
    return HelloWorldCommandName
}

// Basic Hello World
type HelloWorldCommandHandler struct {
    CommandHandler
}

func (cmd HelloWorldCommandHandler) GetName() string {
    return HelloWorldCommandName
}

func (ch HelloWorldCommandHandler) Handle(cmd Command) {
    fmt.Println("Hello World!
----------------------------------------
")
}

// Hello World with Name and Age
type HelloWorldWithNameAndAgeCommandHandler struct {
    CommandHandler
}

func (cmd HelloWorldWithNameAndAgeCommandHandler) GetName() string {
    return HelloWorldCommandName
}

func (ch HelloWorldWithNameAndAgeCommandHandler) Handle(cmd Command) {
    var helloWorldCommand HelloWorldCommand = cmd.(HelloWorldCommand)
    fmt.Println("Hello World! My name is " + helloWorldCommand.Name + " and I'm " + strconv.Itoa(helloWorldCommand.Age) + " years old!
----------------------------------------
")
}


const TodayDateTimeCommandName string = "TodayDateTimeCommand"

// Today's DateTime Command
type TodayDateTimeCommand struct {
    Command
    TimeZone string
}

func (cmd TodayDateTimeCommand) GetName() string {
    return TodayDateTimeCommandName
}


type TodayDateTimeCommandHandler struct {

}

func (ch TodayDateTimeCommandHandler) GetName() string {
    return TodayDateTimeCommandName
}

func (ch TodayDateTimeCommandHandler) Handle(cmd Command) {
    var todayCommand TodayDateTimeCommand = cmd.(TodayDateTimeCommand)
    location, err := time.LoadLocation(todayCommand.TimeZone)
    if err != nil {
        fmt.Errorf("Could not load the Location of the TimeZone. %f", err.Error())
        return
    }
    current_time := time.Now().In(location)
    fmt.Println("Today's date and time is " + current_time.String() + " for the time zone: " + todayCommand.TimeZone)
}


// The CommandHandler Manager
type CommandHandlerManager struct {
    CommandHandlers []CommandHandler
}

func (chm CommandHandlerManager) Publish(cmd Command) {

    for _, cmdHandler := range chm.CommandHandlers {
        if cmd.GetName() == cmdHandler.GetName() {
            cmdHandler.Handle(cmd)
        }
    }
}


func main() {

    fmt.Println("Hey my friend!


")

    cmdHandlerManager := CommandHandlerManager {
        CommandHandlers: []CommandHandler {
            HelloWorldCommandHandler {},
            HelloWorldWithNameAndAgeCommandHandler {},
            TodayDateTimeCommandHandler {},
        },
    };

    cmd := HelloWorldCommand {Name: "ManBear", Age: 357}
    cmdHandlerManager.Publish(cmd)

    fmt.Println("~~~~~~~~ other command published ~~~~~~~~~~~~~~~~~~~~~")
    cmd2 := TodayDateTimeCommand{ TimeZone: "America/Montreal" }
    cmdHandlerManager.Publish(cmd2)
}
  • 写回答

1条回答 默认 最新

  • dongyu4863 2016-09-03 21:02
    关注

    the signature of Handle has to be exactly func (ch HelloWorldCommandHandler) Handle(cmd Command) { to implement the interface. A quick fix would be to do a type assertion at the beginning of your Handle function to get the HelloWorldCommand from your Command)

    But I think this might be a symptom of a possible design issue: if the polymorphism is on Command, maybe command should handle/run itself? maybe with a Run() error in the interface?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建