Ok dafhi, let's review a simpler example of the Dependency Inversion Principle, perhaps it's easier this way for you to grasp the concept, and will help you to find the abstractions you need. I'll be using a similar example to the one proposed on chapter 11 of the book 'Agile Principles, Patterns and Practices in C#', by Robert C. Martin.
Suppose you want to write code that allows you to switch devices on and off with the keyboard. So far, you have a single device: a lamp. So, if you were to express a solution using OO techniques, you can write something like this:
Code: Select all
type Lamp extends Object
public:
declare constructor()
declare destructor()
declare sub turnOn()
declare sub turnOff()
end type
constructor Lamp()
end constructor
destructor Lamp()
end destructor
sub Lamp.turnOn()
? "Lamp has been turned on"
end sub
sub Lamp.turnOff()
? "Lamp has been turned off"
end sub
type Switch
public:
declare constructor()
declare destructor()
declare sub on()
declare sub off()
private:
m_lamp as Lamp
end type
constructor Switch()
end constructor
destructor Switch()
end destructor
sub Switch.on()
m_lamp.turnOn()
end sub
sub Switch.off()
m_lamp.turnOff()
end sub
/'
Main code
'/
var aSwitch = Switch()
dim as string keyPressed
do
keyPressed = input( 1 )
if( keyPressed = "L" ) then
aSwitch.off()
end if
if( keyPressed = "l" ) then
aSwitch.on()
end if
sleep( 1, 1 )
loop until( keyPressed = chr( 27 ) )
That does it, but is somewhat inflexible. In this case, the Switch 'composes' a Light instance, but it is a hardcoded one. I can't change which lamp the Switch class switches, nor can I use it to switch other models of lamp, or other devices that can need a switch. So, we can refactor the design to accept a
dependency to a Lamp, instead of hardcoding it:
Code: Select all
type Lamp extends Object
public:
declare constructor()
declare destructor()
declare sub turnOn()
declare sub turnOff()
end type
constructor Lamp()
end constructor
destructor Lamp()
end destructor
sub Lamp.turnOn()
? "Lamp has been turned on"
end sub
sub Lamp.turnOff()
? "Lamp has been turned off"
end sub
type Switch
public:
declare constructor( _
byref as Lamp )
declare destructor()
declare sub on()
declare sub off()
private:
declare constructor()
m_lamp as Lamp = any
end type
constructor Switch()
end constructor
constructor Switch( _
byref aLamp as Lamp )
m_lamp = aLamp
end constructor
destructor Switch()
end destructor
sub Switch.on()
m_lamp.turnOn()
end sub
sub Switch.off()
m_lamp.turnOff()
end sub
/'
Main code
'/
var aLamp = Lamp()
var aSwitch = Switch( aLamp )
dim as string keyPressed
do
keyPressed = input( 1 )
if( keyPressed = "L" ) then
aSwitch.off()
end if
if( keyPressed = "l" ) then
aSwitch.on()
end if
sleep( 1, 1 )
loop until( keyPressed = chr( 27 ) )
So now we can use the Switch class to switch
any Lamp. However, the dependency of Switch upon Lamp can (and should) be abstracted. This is because the
concept that the Switch class encapsulates doesn't need to know, nor it has to care,
what it is switching. In this case, we are violating the DIP by making a class (Switch) depend upon details (how the Lamp class is implemented). We can improve this by
inverting the dependency relationship: instead of Lamp being depended on by Switch, we make Lamp the depending class:
Code: Select all
type ISwitchableDevice extends Object
declare virtual destructor()
declare abstract sub turnOn()
declare abstract sub turnOff()
end type
destructor ISwitchableDevice()
end destructor
type Lamp extends ISwitchableDevice
public:
declare constructor()
declare destructor() override
declare sub turnOn() override
declare sub turnOff() override
end type
constructor Lamp()
end constructor
destructor Lamp()
end destructor
sub Lamp.turnOn()
? "Lamp has been turned on"
end sub
sub Lamp.turnOff()
? "Lamp has been turned off"
end sub
type Switch
public:
declare constructor( _
byref as ISwitchableDevice )
declare destructor()
declare sub on()
declare sub off()
private:
declare constructor()
m_device as ISwitchableDevice ptr
end type
constructor Switch()
end constructor
constructor Switch( _
byref aSwitchableDevice as ISwitchableDevice )
m_device = @aSwitchableDevice
end constructor
destructor Switch()
end destructor
sub Switch.on()
m_device->turnOn()
end sub
sub Switch.off()
m_device->turnOff()
end sub
/'
Main code
'/
var aLamp = Lamp()
var aSwitch = Switch( aLamp )
dim as string keyPressed
do
keyPressed = input( 1 )
if( keyPressed = "L" ) then
aSwitch.off()
end if
if( keyPressed = "l" ) then
aSwitch.on()
end if
sleep( 1, 1 )
loop until( keyPressed = chr( 27 ) )
By creating an abstract interface to handle the dependency, we have effectively
inversed the relationship: Lamp is now doing the depending (since it has to implement the ISwitchableDevice interface to allow it to be used with a Switch), rather than being depended on. Also, Switch will be able to handle devices that aren't invented yet, without changing its implementation:
Code: Select all
type ISwitchableDevice extends Object
declare virtual destructor()
declare abstract sub turnOn()
declare abstract sub turnOff()
end type
destructor ISwitchableDevice()
end destructor
type Lamp extends ISwitchableDevice
public:
declare constructor()
declare destructor() override
declare sub turnOn() override
declare sub turnOff() override
end type
constructor Lamp()
end constructor
destructor Lamp()
end destructor
sub Lamp.turnOn()
? "Lamp has been turned on"
end sub
sub Lamp.turnOff()
? "Lamp has been turned off"
end sub
type Motor extends ISwitchableDevice
public:
declare constructor()
declare destructor() override
declare sub turnOn() override
declare sub turnOff() override
end type
constructor Motor()
end constructor
destructor Motor()
end destructor
sub Motor.turnOn()
? "The motor has been turned on"
end sub
sub Motor.turnOff()
? "The motor has been turned off"
end sub
type Switch
public:
declare constructor( _
byref as ISwitchableDevice )
declare destructor()
declare sub on()
declare sub off()
private:
declare constructor()
m_device as ISwitchableDevice ptr
end type
constructor Switch()
end constructor
constructor Switch( _
byref aSwitchableDevice as ISwitchableDevice )
m_device = @aSwitchableDevice
end constructor
destructor Switch()
end destructor
sub Switch.on()
m_device->turnOn()
end sub
sub Switch.off()
m_device->turnOff()
end sub
/'
Main code
'/
var aLamp = Lamp()
var aMotor = Motor()
var aSwitch = Switch( aLamp )
var anotherSwitch = Switch( aMotor )
dim as string keyPressed
do
keyPressed = input( 1 )
if( keyPressed = "M" ) then
anotherSwitch.off()
end if
if( keyPressed = "m" ) then
anotherSwitch.on()
end if
if( keyPressed = "L" ) then
aSwitch.off()
end if
if( keyPressed = "l" ) then
aSwitch.on()
end if
sleep( 1, 1 )
loop until( keyPressed = chr( 27 ) )
You can also provide the dependency to Switch by using a different injection scheme:
Code: Select all
type ISwitchableDevice extends Object
declare virtual destructor()
declare abstract sub turnOn()
declare abstract sub turnOff()
end type
destructor ISwitchableDevice()
end destructor
type Lamp extends ISwitchableDevice
public:
declare constructor()
declare destructor() override
declare sub turnOn() override
declare sub turnOff() override
end type
constructor Lamp()
end constructor
destructor Lamp()
end destructor
sub Lamp.turnOn()
? "Lamp has been turned on"
end sub
sub Lamp.turnOff()
? "Lamp has been turned off"
end sub
type Motor extends ISwitchableDevice
public:
declare constructor()
declare destructor() override
declare sub turnOn() override
declare sub turnOff() override
end type
constructor Motor()
end constructor
destructor Motor()
end destructor
sub Motor.turnOn()
? "The motor has been turned on"
end sub
sub Motor.turnOff()
? "The motor has been turned off"
end sub
type Switch extends Object
public:
declare constructor()
declare destructor()
declare sub on( _
byval as ISwitchableDevice ptr )
declare sub off( _
byval as ISwitchableDevice ptr )
end type
constructor Switch()
end constructor
destructor Switch()
end destructor
sub Switch.on( _
byval aDevice as ISwitchableDevice ptr )
aDevice->turnOn()
end sub
sub Switch.off( _
byval aDevice as ISwitchableDevice ptr )
aDevice->turnOff()
end sub
/'
Main code
'/
var aLamp = Lamp()
var aMotor = Motor()
var aSwitch = Switch()
dim as string keyPressed
do
keyPressed = input( 1 )
if( keyPressed = "M" ) then
aSwitch.off( @aMotor )
end if
if( keyPressed = "m" ) then
aSwitch.on( @aMotor )
end if
if( keyPressed = "L" ) then
aSwitch.off( @aLamp )
end if
if( keyPressed = "l" ) then
aSwitch.on( @aLamp )
end if
sleep( 1, 1 )
loop until( keyPressed = chr( 27 ) )
I hope that you're able to see how the different concepts fit into what you're trying to accomplish.