I tried to go magic with a little reflection in Go(lang) ...
Unlike (some) other programming languages in Go reflection is considered ok for using it in production code. Which does not mean it should be used without a good reason.
I tried to implement a command handler in a different way than switch/case given the interface of the command handler can stay as it is:
type CommandHandler interface { Handle(command Command) error }
The advantage of having a single entry point is that it’s simple to wrap each handled command with generic functionality, e.g. transactional stuff. The only disadvantage of using a switch/case it that this is quite ugly, especially if the command handler grows and has to handle lot’s of commands.
Obviously I tried to solve this with reflection and I got it working:
package application import ( "errors" "myproject/customer/model" "myproject/customer/model/commands" "myproject/shared" "reflect" ) type commandHandlerWithReflection struct { customers model.Customers } func NewCommandHandlerWithReflection(persons model.Customers) *commandHandlerWithReflection { return &commandHandlerWithReflection{customers: persons} } func (handler *commandHandlerWithReflection) Handle(command shared.Command) error { if command == nil { return errors.New("commandHandler - nil command handled") } method, ok := reflect.TypeOf(handler).MethodByName(command.CommandName()) if !ok { return errors.New("commandHandler - unknown command handled") } in := make([]reflect.Value, 2) in[0] = reflect.ValueOf(handler) // method receiver in[1] = reflect.ValueOf(command) // first input param - the command response := method.Func.Call(in) switch response[0].Interface().(type) { case error: return response[0].Interface().(error) case nil: return nil default: return errors.New("commandHandler - unexpected type returned when command was handled") } } func (handler *commandHandlerWithReflection) Register(register commands.Register) error { newCustomer := model.NewUnregisteredCustomer() if err := newCustomer.Apply(register); err != nil { return err } if err := handler.customers.Save(newCustomer); err != nil { return err } return nil } func (handler *commandHandlerWithReflection) ConfirmEmailAddress(confirmEmailAddress commands.ConfirmEmailAddress) error { customer, err := handler.customers.FindBy(confirmEmailAddress.ID()) if err != nil { return err } if err := customer.Apply(confirmEmailAddress); err != nil { return err } if err := handler.customers.Save(customer); err != nil { return err } return nil }
But there is one issue with that solution: The methods which the Handle() method dispatches to should be private, as they are not part of the public interface!
Even if NewCommandHandlerWithReflection() would return an interface instead of the concrete object, which is not idiomatic in Go (and I will only bend this rule with a very good reason), any client of the command handler could still simply typecast it to the concrete object.
Unfortunately Go's reflection does not support unexported methods. The conceptual reason is that this would render the whole exported/unexported paradigm quite useless. I wish it would support that from within the same package, like in my usecase. There might be technical reasons apart from conceptual reasons, though.
So once more when I played with reflection in Go it did not end up in an acceptable solution, but at least I have learned how to do it. ;-)
Luckily there is no real issue with using switch/case for dispatching instead, so I'll just stick with that.














