In trying to separate interface from implementation, I ran into a circular dependency problem.
There is a best practice in the world of Java: consume interfaces instead of concrete classes. That is, instead of declaring variables of type ArrayList<int>
, use the type List<int>
instead. That way the migration from ArrayList
to your own implementation of List
will be painless.
I have decided to write an event queue/bus in golang for fun. Consumers are able to subscribe to certain topics and publish events within certain topics.
I have decided to split the interface and implementation in case I'll have to write adapters to already existing solutions, like RabbitMQ, in the future.
First I defined the interface:
package eventQueue
type EventQueue interface {
Subscribe(topic string, handlerFunc HandlerFunc)
Publish(topic string, event interface{})
}
type HandlerFunc func(event interface{})
And, within the internal
package, I have written the basic implementation:
package internal
import (
"eventQueue"
"sync"
)
type EventQueueImpl struct {
handlerFuncsByTopic map[string][]eventQueue.HandlerFunc
mutex sync.RWMutex
}
// Implements the interface...
Back to the interface - I have written a New()
method, which returns the default implementation (at the moment there is, of course, only one):
func New() EventQueue {
return &internal.EventQueueImpl{} // EventQueueImpl uses pointer receivers
}
And there it is. EventQueueImpl
imports HandlerFunc
from eventQueue
, and the eventQueue
package imports EventQueueImpl
.
How to change this design to circumvent circular dependency while preserving the interface-implementation separation?
Is dependency injection a fitting solution?