473,396 Members | 2,039 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Dependency Inversion Principle Dilemma

Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.

However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).

So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?
Can one keep a Triangle simplified so it is just a
Triangle class?

Otherwise, one would have to keep modifying the base
Shape class everytime a new display device comes up.
{Or any other entity that would need to know the
type of shape}.
--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #1
12 2394
This will only be a "me too" answer, I'm afraid.

Thomas Matthews wrote:
Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.

However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).
That's exactly the problem that I have with this. A triangle should not
know that it can be drawn, or what class is responsible for drawing
triangles. It should only be a container for the three vertices and
maybe contain some triangle specific functions (area, center of mass or
whatever).
So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?
Can one keep a Triangle simplified so it is just a
Triangle class?
Sorry, I don't know any good way, but I'd be interested in it, too.
Otherwise, one would have to keep modifying the base
Shape class everytime a new display device comes up.
{Or any other entity that would need to know the
type of shape}.


Not only the base class, but also every derived one. And if you want to
reuse your class hierarchy e.g. for writing a file conversion tool
can't draw at all, you'd either have to make a dummy renderer or edit
all the classes to remove the draw function.

Jul 22 '05 #2
On Thu, 18 Dec 2003 18:32:54 GMT, Thomas Matthews <Th****************************@sbcglobal.net> wrote:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).
Apart from the above being nonsense C++ (it would be better with
'struct' instead of 'class') this is off-topic in this group.

Try instead e.g. [comp.programming].

So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?


Use an abstract interface.
struct ICanvas
{
virtual void setPixel( Point const& pos, Color const& aColor = Color::black ) = 0;
};
struct Shape
{
virtual void drawAt( Point const& upperLeft, ICanvas& aCanvas ) = 0;
};

Jul 22 '05 #3
Thomas Matthews wrote:
Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.
That's the traditional OO approach. Sometimes it's appropriate, but
often it's not.
However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).

So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?
Can one keep a Triangle simplified so it is just a
Triangle class?

Otherwise, one would have to keep modifying the base
Shape class everytime a new display device comes up.
{Or any other entity that would need to know the
type of shape}.


// Use overloaded functions.

namespace Shapes
{
class Shape { /* ... */ };
class Square: public Shape { /* ... */ };
class Triangle: public Shape { /* ... */ };
}

namespace Display
{
void draw( Shapes::Shape const& ) { /* ... * }
void draw( Shapes::Square const& ) { /* ... * }
void draw( Shapes::Triangle const& ) { /* ... * }
}

Jul 22 '05 #4
Alf P. Steinbach wrote:
On Thu, 18 Dec 2003 18:32:54 GMT, Thomas Matthews <Th****************************@sbcglobal.net> wrote:

class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).

Apart from the above being nonsense C++ (it would be better with
'struct' instead of 'class') this is off-topic in this group.

Try instead e.g. [comp.programming].

I believe that technically you are correct that is is not so
much a language issue as an OO one.

The classes are nonsense but are the typical example used
by many authors and instructors. I thought this would
be more familiar to readers than my current implementation.
So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?

Use an abstract interface.
struct ICanvas
{
virtual void setPixel( Point const& pos, Color const& aColor = Color::black ) = 0;
};
struct Shape
{
virtual void drawAt( Point const& upperLeft, ICanvas& aCanvas ) = 0;
};

In your example, the Shape class still has a drawAt method.
If I want to store shapes into a database, then I would have
to change the Shape class and add a method for database
access:
enum Action_Type(DB_STORE, DB_RETRIEVE, DB_SEARCH};

struct Shape /* or class */
{
virtual void draw(); // or drawAt
virtual void database(Action_Type);
};

In my application, a Reference Database System, references can
be created by Text_Stream, User_Interface and Database. In a
simple situation, the Text_Stream creates a reference subobject
(like book, magazine, newspaper, etc.) and returns a pointer
to the base class, "Reference". The next step is to display
the object via the User_Interface. This is where the dilemma
begins. I would like to have each reference stored in a
different "view" (i.e. page, listbox, panel, etc.) based on
its kind (type). For example, all of the books would be
displayed together as will all the magazines.

The D.I.P. states that the objects should have a "display"
method. However, in order for the object to display its
data, it must know some details about the User_Interface.
Thus the violation of the Integration Separation Principle (ISP).

Although one idea is to create an interface class for
references with interactions with the User_Interface:
struct Reference
{
};

struct Reference_with_UI
: public Reference
{
virtual void display(/*???*/);
};

struct Book
// : public Reference /* original inheritance */
: public Reference_with_UI
{
virtual void display(/* ??? */);
}

The above implementation takes the interface out of the
base class, but the child classes still have to know
details about the User_Interface (such as which view
to display in).

Perhaps, as you suggested, I should move this over to
news:comp.programming or news:comp.object.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #5
Jeffrey Schwab wrote:
Thomas Matthews wrote:
Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.

That's the traditional OO approach. Sometimes it's appropriate, but
often it's not.

Agreed. Sometimes pure OO is dificult.
However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).

So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?
Can one keep a Triangle simplified so it is just a
Triangle class?

Otherwise, one would have to keep modifying the base
Shape class everytime a new display device comes up.
{Or any other entity that would need to know the
type of shape}.

// Use overloaded functions.

namespace Shapes
{
class Shape { /* ... */ };
class Square: public Shape { /* ... */ };
class Triangle: public Shape { /* ... */ };
}

namespace Display
{
void draw( Shapes::Shape const& ) { /* ... * }
void draw( Shapes::Square const& ) { /* ... * }
void draw( Shapes::Triangle const& ) { /* ... * }
}

Now the dilemma moves to the draw() function. The draw()
function needs to get the data from the Shape. Although
I do like this version better.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

Jul 22 '05 #6
Thomas Matthews wrote:
The D.I.P. states that the objects should have a "display"
method. However, in order for the object to display its
data, it must know some details about the User_Interface.
Thus the violation of the Integration Separation Principle (ISP).


Not necessarily. By definition a "shape" is a displayable thing,
so it can certainly possess *some* knowledge about that. Ideally,
that knowledge should be very abstract and designed to work with
varying types of displays.

I think a good technique--which you've touched on already--is that
your draw methods take a parameter that is an interface to the
"canvas". By deriving from the "canvas" class, you can allow your
shapes to drawn on anything.

--
|_ CJSonnack <Ch***@Sonnack.com> _____________| How's my programming? |
|_ http://www.Sonnack.com/ ___________________| Call: 1-800-DEV-NULL |
|_____________________________________________|___ ____________________|
Jul 22 '05 #7
Thomas Matthews wrote:
Jeffrey Schwab wrote:
Thomas Matthews wrote:
Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.


That's the traditional OO approach. Sometimes it's appropriate, but
often it's not.


Agreed. Sometimes pure OO is dificult.
However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).

So how does one implement (or not violate) the Dependency
Inversion principle without violating the encapsulation
by require details of external interfaces?
Can one keep a Triangle simplified so it is just a
Triangle class?

Otherwise, one would have to keep modifying the base
Shape class everytime a new display device comes up.
{Or any other entity that would need to know the
type of shape}.


// Use overloaded functions.

namespace Shapes
{
class Shape { /* ... */ };
class Square: public Shape { /* ... */ };
class Triangle: public Shape { /* ... */ };
}

namespace Display
{
void draw( Shapes::Shape const& ) { /* ... * }
void draw( Shapes::Square const& ) { /* ... * }
void draw( Shapes::Triangle const& ) { /* ... * }
}

Now the dilemma moves to the draw() function. The draw()
function needs to get the data from the Shape. Although
I do like this version better.


The information needed by the display can be provided by accessors in
the Shape classes. If the information needed to display the objects
really should not be public, but is an implementation detail, then so is
the act of displaying. In that case, draw *should* be a member of the
original Shape classes.

-Jeff

Jul 22 '05 #8
> The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).


The solution is that the draw method should draw to an
abstract device context. Thus you will not need to modify
any of the shape family of classes when a new display device
is introduced.

BTW, Here is another article on the Dependency Inversion Principle:
http://www.eventhelix.com/RealtimeMa..._principle.htm

Sandeep
--
http://www.EventHelix.com/EventStudio
EventStudio 2.0 - Generate Sequence Diagrams and Use Case Diagrams in
PDF
Jul 22 '05 #9
EventHelix.com wrote:
The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).
The solution


/A/ solution. ;)
is that the draw method should draw to an
abstract device context. Thus you will not need to modify
any of the shape family of classes when a new display device
is introduced.

BTW, Here is another article on the Dependency Inversion Principle:
http://www.eventhelix.com/RealtimeMa..._principle.htm

Sandeep
--
http://www.EventHelix.com/EventStudio
EventStudio 2.0 - Generate Sequence Diagrams and Use Case Diagrams in
PDF


Jul 22 '05 #10
Rolf Magnus <ra******@t-online.de> wrote in message news:<br*************@news.t-online.com>...
This will only be a "me too" answer, I'm afraid.

Thomas Matthews wrote:
Hi,

According to Robert Martin's Dependency Inversion Principle,
http://www.objectmentor.com/resources/articles/dip.pdf,
when there is a need to test the type of an object, the
code inside the "switch cases" should be placed into the
parent class.

However, I am finding that this conflicts with the other
principles -- the objects now must know details about
objects outside their own encapsulation.

For example, using the Shape class:
class Shape
{
virtual void draw() = 0;
};

class Square
: public Shape
{
void draw();
};

class Triangle
: public Shape
{
void draw();
};

The above "draw" methods must know something about the
external environment in order to draw their shape. I
believe this conflicts with the Integration Separation
Principle as well as the K.I.S.S. (Keep It Simple (and)
Stupid).


That's exactly the problem that I have with this. A triangle should not
know that it can be drawn, or what class is responsible for drawing
triangles. It should only be a container for the three vertices and
maybe contain some triangle specific functions (area, center of mass or
whatever).


No, a triangle should be whatever it is needs to be to meet the
application requirements, consistent with the name "Triangle". I
wouldn't like to find a Triangle class that really implemented a
quadrilateral, but other than that there's no way to say what should
or should not be supported by a Triangle class. It's an engineering
decision. Throwing functions out of the Triangle class means that
they have to be somewhere else. If you throw out draw(), then instead
of just Triangle, you might have Triangle and PolygonDrawer. Is that
a simpler, or more complex? There's no way to answer that without
seeing the rest of the application.
Jul 22 '05 #11
> > That's exactly the problem that I have with this. A triangle should not
know that it can be drawn, or what class is responsible for drawing
triangles. It should only be a container for the three vertices and
maybe contain some triangle specific functions (area, center of mass or
whatever).


On the contrary - A triangle should know that it can be drawn if the
application requires it to be drawn.
To see that this is so just consider the more common

virtual void print(ostream&) const = 0;

I doubt that you would argue that it shouldn't know how to print itself and
drawing is just printing in 2D.

The reason that most people don't see it this way is that whilst C++ has a
standard way of printing characters it has no standard
way of drawing. I was brought around to this point of view by an excellent
article on Java which does have a standard GUI (Unfortunately Java people
still mainly write non-object oriented code because of beans but this is
just warping the OO paradigm to suit tool vendors)

It is quite likely that you actually need more than one type of triangle -
one to represent the basic mathematical abstraction and one to do the more
complicated stuff either deriving from the simple class or containing it.
This is also a very common situation and totally in keeping with KISS.


Jul 22 '05 #12
Nicholas Hounsome wrote:
That's exactly the problem that I have with this. A triangle should not
know that it can be drawn, or what class is responsible for drawing
triangles. It should only be a container for the three vertices and
maybe contain some triangle specific functions (area, center of mass or
whatever).

On the contrary - A triangle should know that it can be drawn if the
application requires it to be drawn.
To see that this is so just consider the more common

virtual void print(ostream&) const = 0;


Just 'cause it's common doesn't necessarily mean it's the best way.
This kind of design leads to huge, bloated classes. OK, so you think
your triangle needs to know how to print itself, and how to draw itself.
What's next? Computations of things like area, centroid, etc. OK,
after that? How about rotation/translation/other transforms? In 2D?
How about in 3D? After all, a 2D triangle can exist within a 3D space.
Then maybe we'll add some real-time animation, serialization,
collision detection, etc., etc., etc. See what I mean? What started
out as a nice fifty-line class could end up being a 100K source file,
and so fat and bloated that it's of no use to anyone without a 40-hour
seminar and an O'Reilly animal-cover book.

--
Mike Smith

Jul 22 '05 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

18
by: Ken | last post by:
Hi. Can anyone refer me to any articles about the compatibility between c++ polymorphism and real-time programming? I'm currently on a real-time c++ project, and we're having a discussion...
3
by: DJTN | last post by:
I'm getting the following error when I try to compile my setup project in VS 2002. I have re-installed the .net framework 1.1 and it didnt solve the problem. WARNING: Unable to find dependency...
2
by: Tanari | last post by:
I'm interested in learning about using Context Inversion of Control in c++, but all of the examples I can find use C# or Java. Can someone direct me to an example of Context IoC written in C++? ...
14
by: pamelafluente | last post by:
Hi guys, I have a hard problem :) I have the following situation: <span onmouseover = "SelectionEffect()"> <div style="width: 50px; height: 50px; background-color:#FFE4E1"></div> </span>
3
by: lancered | last post by:
Hi dear all, I am using Python2.4.2+NumPy1.0.1 to deal with a parameter estimation problem with the least square methods. During the calculations, I use NumPy package to deal with matrix...
2
by: sweetchuck74 | last post by:
Nowadays, DI (Dependency Inversion) is one of the widely used design pattern. It provides several benefits, such as (1) loose coupling between component (2) effective and easy testing (component...
3
by: PeteJ | last post by:
Hello all.. I wrote code in C to invert n x n matrices, where 1<n<39 and the matrices are guaranteed to be invertible. Prior to this task, I haven't really seen linear algebra since my sophmore...
5
by: jayagowri | last post by:
Can anyone explain me the concept of inversion of control in spring pls
3
by: Danno | last post by:
Just that simple question....out of curiosity.
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.