An issue I came across designing a Window that is platform independent for a graphics software. I require each window implements a Launch() function, and has a size.
My current solution is a struct called BaseWindow that has Size embedded and an interface called Window with Launch() and GetSize(). An OpenGLWindow for example will then embed BaseWindow and implement Launch() using openGL calls. I feel this isn't correct because of a few code smells. A) I don't like it having to be called GetSize(). But if I call it Size() it conflicts with the Size field of the embedded size struct in BaseWindow. B) Interfaces should be implementation independent, but these getters are pretty close to forcing implementation.
I would like in the end to have a single type Window to pass around and use without worrying about the implementation of which platform it's on.
// What I have
type Size struct {
Width int
Height int
}
// What I would like to be my type that I use to access these functions/members
type Window interface {
GetSize() Size
Launch() error
}
// This would have more things in the final application, but for simplicity
// I only included Size
type BaseWindow struct {
Size
}
// Example of what I want my end result to look like
type OpenGLWindow {
BaseWindow
}
func (window OpenGLWindow) Launch() {
// Do stuff
}
// Notice Window returns size of BaseWindow and uses Launch of OpenGLWindow
func SetGlobalWin(window Window) {
GlobalWin = window
CirclePositionX = window.GetSize().Width / 2
window.Launch()
}
// If using openGL, open openGL window and use that as primary window
func UseMyWindow() {
glwin := NewOpenGLWindow()
SetGlobalWin(glwin)
}
While this approach works, it doesn't seem like a good solution for reasons stated above. I have a feeling I'm trying too hard to make Launch() act like a virtual function from oop and am missing some fundamental design patterns for Go's more composition based approach.