refactor to use interfaces and abstract classes where possible