By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,606 Members | 3,802 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,606 IT Pros & Developers. It's quick & easy.

tightly coupled class design problem

P: n/a


Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no way
around this. The pointer is required for the construction and drawing of the
sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface* s);

...

...

}

....

....

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the objects
sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

But then this raised other issues like, how do I handle what happens if i
try to draw the object before creating its sprite.

Any thoughts on this?

Dean
Jan 27 '06 #1
Share this Question
Share on Google+
19 Replies


P: n/a

"Chocawok" <no****@nospam.com> wrote in message
news:3N********************@fe3.news.blueyonder.co .uk...


Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no way
around this. The pointer is required for the construction and drawing of
the sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface* s);

...

...

}

...

...

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the
objects sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

But then this raised other issues like, how do I handle what happens if i
try to draw the object before creating its sprite.


A simple approach could be:

Continue to use a MyClass ctor (for all ctors) argument for your
pointer, but always give it a default value (e.g. 0). Then
have your draw functions check this pointer before using it.

-Mike
Jan 27 '06 #2

P: n/a
On Fri, 27 Jan 2006 23:11:59 +0000, Chocawok wrote:
<snip>
The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no way
around this.
The pointer is required for the construction and drawing of the
sprite object.


Question: when you say "There is no way around this.", do you mean that
the current class design requires it, or that some underlying issue
requires you to design the class this way? In other words, could you
change the Sprite class to not take the VideoSurface at construction time
but rather at draw time?

My problem is this:

This design means that I have to pass the pointer to the video surface to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface* s);
This implies that "this_objects_sprite" is actually a "Sprite *" (not
"Sprite").

...

...

}

...

...

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the objects
sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

That would work. If you can change Sprite's semantics, you could also
potentially still allow the construction of the sprite, but have an
"attach" method to later connect it to a video surface.


But then this raised other issues like, how do I handle what happens if i
try to draw the object before creating its sprite.


If the sprite member is a pointer, initialize it to 0 in the constructor
and check. Additionally, if somehow the "draw" method knows about the
video surface (e.g. it's passed as a parameter), you could create the
sprite the first time you try to draw if it hasn't been created yet.

- Jay

Jan 27 '06 #3

P: n/a
In article <3N********************@fe3.news.blueyonder.co.uk> ,
"Chocawok" <no****@nospam.com> wrote:
Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.
The fact that you have a Sprite object contained within your MyClass
object is what is making it tightly coupled to the graphics system. If
you don't want that coupling, you need to abstract it out.

If you can't change the Sprite class, then you will have to use an
Adaptor.

class Image {
public:
virtual ~Image() { }
virtual void draw() = 0;
};

class SpriteAdaptor : public Image {
Sprite _sprite;
public:
SpriteAdaptor( VideoSurface* s ): _sprite( s ) { }
void draw() {
_sprite.draw();
}
};

class MyClass {
Image* _image;
public:
MyClass( Image* i ): _image( i ) { assert( i ); }
// call _image->draw() in some member-function
};
I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the objects
sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);


You can do that, but the coupling still exists in that case. MyClass has
to include the Sprite header and possibly the VideoSurface header as
well.
Jan 28 '06 #4

P: n/a

Chocawok wrote:
Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no way
around this. The pointer is required for the construction and drawing of the
sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface to
myclass in its constructor, e.g.


The broken part of this design is that Sprite "knows how to draw
itself", and hence must take a pointer to a Surface. Sprite sounds like
a value-semantic type to me, so what you need is a utility that draws
Sprites given a Sprite and a Surface:

class Sprite {...};

class MyObject {
Sprite d_sprite;
//...
public:
const Sprite& sprite() const { return d_sprite; }
};

struct DrawUtil {
static int draw(const Sprite& sprite, const Surface& surface);
};

Jan 28 '06 #5

P: n/a
The following is a message I came across on comp.lang.c++, it sounded
like a good topic of discussion for comp.object as well, so I'm
forwarding it here...

========== Begin Forwarded Message ==========
From: "Chocawok" <no****@nospam.com>
Subject: tightly coupled class design problem
Date: Fri, Jan 27, 2006 6:11 PM

Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no
way
around this. The pointer is required for the construction and drawing of
the
sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface
to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface*
s);

...

...

}

....

....

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the
objects
sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

But then this raised other issues like, how do I handle what happens if
i
try to draw the object before creating its sprite.

Any thoughts on this?

Dean
Jan 28 '06 #6

P: n/a
Hi,

Maybe you should abstract away the Graphics system as well as surfaces.

For instance assume Sprite should, for performance reasons, create some
surface in the graphics system (if that is possible for that graphics system
on GDI based system it would just use system memory).
For instance:
---------------------------------------------------------------------------------
#include <list>
using namespace std;

// Generic Class that holds a piece of memory to prepare sprite on (could be
located on the graphics card in system core or ....
class GRGB;
class GSprite;
class GSurface
{
private:
unsigned long Width,Height;
public:
GSurface( unsigned long Width, unsigned long Height ):
Width( Width ),
Height( Height )
{
}
// Draw
virtual void Prepare( unsigned long X, unsigned long Y, unsigned
long Width, GRGB *BunchOfRgbValues ) = 0;

};

class GGDISurface : public GSurface
{
public:
// New some memory from the heap on construction
GGDISurface( unsigned long Width, unsigned long Height ):
GSurface( Width, Height )

{
// Do stuff
}
// GDI Implementation draw on a piece of system memory, this is to
prepare the sprite
virtual void Prepare( unsigned long X, unsigned long Y, unsigned
long Width, GRGB *BunchOfRgbValues )
{
}
};

class GDirectXSurface : public GSurface
{
public:
// Get some memory from the graphics card on construction
GDirectXSurface( unsigned long Width, unsigned long Height ):
GSurface( Width, Height )
{}
// DirectX Implementation draw on the piece of memory on the
graphics card
virtual void Prepare( unsigned long X, unsigned long Y, unsigned
long Width, GRGB *BunchOfRgbValues )
{
}
};

class GGraphicsSystem
{
private:
std::list<GSprite*> SpriteList;
public:
virtual void AddSprite( GSprite *Sprite );
virtual GSurface *CreateSurface( unsigned long Width, unsigned long
Height ) = 0;
};

class GDirectXGraphicsSystem : public GGraphicsSystem
{
public:
GDirectXSurface *CreateSurface( unsigned long Width, unsigned long
Height )
{
}
};

class GSprite
{
private:
GSurface *Surface;
public:
GSprite( GGraphicsSystem * GraphicsSystem )
{
Surface = GraphicsSystem->CreateSurface( 200, 200 );
GRGB *Values;
Surface->Prepare( 10, 10, 100, Values );
}
// Called by graphic system when sprites need to be redrawn (to keep it
simple I assume the 'real' screen is also a surface
void Draw( GSurface *ScreenSurface )
{
// Draw myself GSurface should also contain some (virtual) methods to
draw GSurfaces on GSurfaces
}
};

int main( int ArgC, char *ArgV[] )
{
return 0;
}
Regards, Ron AF Greve

http://moonlit.xs4all.nl
"Chocawok" <no****@nospam.com> wrote in message
news:3N********************@fe3.news.blueyonder.co .uk...


Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no way
around this. The pointer is required for the construction and drawing of
the sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface* s);

...

...

}

...

...

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the
objects sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

But then this raised other issues like, how do I handle what happens if i
try to draw the object before creating its sprite.

Any thoughts on this?

Dean

Jan 28 '06 #7

P: n/a
"Chocawok" <no****@nospam.com> wrote in
news:3N********************@fe3.news.blueyonder.co .uk:


Some of the classes in my app are graphical.
Interesting, how could such ugly problem happen to them?

To encapsulate the graphical side of things I had created a
class called "sprite" which holds a bit map and knows how to
draw itself etc.

It knows? And could it give that information to something that
is able to use it with knowledge how to talk to the graphic
device/s?

The classes that are graphical contain a sprite object.
I hope quad/oct tree countains just pointers/references to
"sprite" / image/ managedImage objects.
The sprite class requires a pointer to a "video surface". There is no way around this. The pointer is required for the
construction
Incorrect.
and drawing of the sprite object.
If pointer to "drawing surface" / OGL is in different class,
that accepts "sprite" objects, then it's in the only place
where it need to be, in you case.

This design means
Bad design. Imagine what would happen if that pointer would be
volatile.
.........
But then this raised other issues like, how do I handle what
happens if i try to draw the object before creating its sprite.


You have two possibilities. 1. Nothing. 2. Null pointer
exception.

Jan 28 '06 #8

P: n/a
Chocawok wrote:
Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.
MyClass


It seems that if some of your classes are inherently graphical, and
others are not, you can express this by synthesizing the types you need
using multiple inheritance:

class WithSprite : public MyClass, public Sprite
{
} ;

class WithoutSprite : public MyClass
{
} ;

Virtual functions (and perhaps another class) will allow you to deal
with differences between classes that are graphical and classes that
are not.

But again, all of this depends on your big picture.

-Le Chaud Lapin-

Jan 28 '06 #9

P: n/a
I think I have come to a decision.

I think the best solution is to have a Sprite class which handles the
graphics and drawing of itself.

BUT, and this is the new bit, construct the Sprite outside of the container
object. This way the containing object doesn't need to know ANY details of
how the sprite is constructed or how it draws iself.

e.g.

Sprite
{
bitmap i;
VideoSurface* drawingdestination;
Sprite(VideoSurface* s, bitmap b) { drawingdestination = s; i = b}
Draw();
}

MyClass
{
Sprite* s;
void MyClass();
void AttachSprite(Sprite* s) {this.s = s};
void Draw() {s.draw();}
}

main()
{
myobj = new MyClass();
myobj.AttachSprite(new Sprite(videoram, image));
myobj.Draw();
}

This means all the graphics details (DirectX or OpenGL or GDI etc) stay in
the one class, providing nice encapsulation.

I think i was getting confused, because I was trying to abstract away the
very fact that my objects have a graphical side to them. Which didn't make
any sense, because they are graphical in nature.

thanks very much for all your ideas.

Dean
Jan 28 '06 #10

P: n/a
I V
Making the Sprite responsible for knowing what surface to draw itself
on looks like a good decision. However:

Chocawok wrote:
MyClass
{
Sprite* s;
void MyClass();
void AttachSprite(Sprite* s) {this.s = s};
void Draw() {s.draw();}
What happens if you call Draw on a MyClass object before you've called
AttachSprite? At the very least, MyClass::Draw needs to make sure it
has a valid sprite and take appropriate action (perhaps throw an
exception) if not.

However, that's not ideal, because this problem would only show up at
run time, and so you might miss it in your tests. If Draw is essential
to the function of MyClass, then a MyClass object is conceptually
incomplete without a Sprite, and that's a problem. All objects should
have all the information they need to function straight after they have
been constructed. So why not:

class MyClass
{
Sprite* sprite_;
public:
MyClass(Sprite* s)
: sprite_(s)
{ }

void draw()
{ s->draw(); }
};

This means you have to delay constructing the MyClass objects until you
can create the DrawingSurface and the Sprites; maybe that is difficult
for some reason, in which case you might have to go with your
AttachSprite method, but you should probably try and avoid that if you
can.
I think i was getting confused, because I was trying to abstract away the
very fact that my objects have a graphical side to them. Which didn't make
any sense, because they are graphical in nature.


Yes, that sounds right.

Jan 28 '06 #11

P: n/a
This is covered in a similar discussion here:
http://groups.google.com/group/comp....9631a3addff6f9

Just invert the control to the objects that contain the information and
it will be simple.
ie: Always ask the object with the information to do the work.

Rgs, James.
(http://www.jamesladdcode.com)

Jan 28 '06 #12

P: n/a
> run time, and so you might miss it in your tests. If Draw is essential
to the function of MyClass, then a MyClass object is conceptually
incomplete without a Sprite, and that's a problem. All objects should
have all the information they need to function straight after they have
been constructed. So why not:

class MyClass
{
Sprite* sprite_;
public:
MyClass(Sprite* s)
: sprite_(s)
{ }

void draw()
{ s->draw(); }
};

This means you have to delay constructing the MyClass objects until you
can create the DrawingSurface and the Sprites; maybe that is difficult
for some reason, in which case you might have to go with your
AttachSprite method, but you should probably try and avoid that if you


I see your points and your right. Calling the constructor of MyClass with
the Sprite as a parameter seems the way to go.

Thanks for that.

BTW, I'm not familiar with the syntax you've used in part of your code. I
presume:

MyClass(Sprite* s)
: sprite_(s)
{ }
does the same thing as:

MyClass(Sprite* s) { sprite_ = s};
And one final thing, I notice you use an underscore in the sprite variable
name, "sprite_" and somewhere else in the thread someone used "_sprite". Is
there any convention being used here, and if so, what is it?

Thanks

Dean
Jan 29 '06 #13

P: n/a
On Sun, 29 Jan 2006 00:12:36 GMT, "Chocawok" <no****@nospam.com>
wrote:
BTW, I'm not familiar with the syntax you've used in part of your code. I
presume:

MyClass(Sprite* s)
: sprite_(s)
{ }

does the same thing as:

MyClass(Sprite* s) { sprite_ = s};


Grab any good current book on C++ and read about the "Initialization
List."

Also the FAQ has a pretty bad article about it.
http://www.parashift.com/c++-faq-lit....html#faq-10.6

Much Much Much Better Here:
http://www.goingware.com/tips/parame...embervars.html

HTH - Good Luck
Jan 29 '06 #14

P: n/a
I V
Chocawok wrote:
BTW, I'm not familiar with the syntax you've used in part of your code. I
presume:

MyClass(Sprite* s)
: sprite_(s)
{ }

does the same thing as:

MyClass(Sprite* s) { sprite_ = s};
Pretty much. There's a slightly subtle difference which is only likely
to be important if the member variable is itself an instance of a
class. Doing:

class MyClass
{
OtherClass other_;
public:
MyClass(OtherClass o)
{
other_ = o;
}
};

Calls the default constructor of OtherClass to create other_ , and then
the assignment operator to set other_ to o

Wheras:

MyClass(OtherClass o)
: other_(o)
{ }

doesn't call the default constructor of OtherClass, but calls the copy
constructor to make other_ be a copy of o. This may be significant if
the default constructor takes a long time, or if OtherClass doesn't
_have_ a default constructor. It's probably a good idea to use the
initializer list, as that makes it clear to people reading the source
that you are just initializing your members, rather than doing anything
else.
And one final thing, I notice you use an underscore in the sprite variable
name, "sprite_" and somewhere else in the thread someone used "_sprite". Is
there any convention being used here, and if so, what is it?


It's a moderately common convention to mark member variables with an
underscore, either at the beginning or the end; some people use a
naming convention like m_member instead.

Jan 29 '06 #15

P: n/a
* JustBoo:
On Sun, 29 Jan 2006 00:12:36 GMT, "Chocawok" <no****@nospam.com>
wrote:
BTW, I'm not familiar with the syntax you've used in part of your code. I
presume:

MyClass(Sprite* s)
: sprite_(s)
{ }

does the same thing as:

MyClass(Sprite* s) { sprite_ = s};
Grab any good current book on C++ and read about the "Initialization
List."

Also the FAQ has a pretty bad article about it.
http://www.parashift.com/c++-faq-lit....html#faq-10.6


What do you think is "bad"?

Much Much Much Better Here:
http://www.goingware.com/tips/parame...embervars.html


This article is sometimes misleading and incorrect.

Let's start with the very first sentence:

"Member variables must be initialized in the constructor's
initialization list."

That's false.

First part of sentence 2:

"Smart pointer members minimize dependencies"

That's generally false.

Second part of sentence 2:

"while allowing exception safety."

That's misleading: smart pointers don't just allow exception safety, and
their exception safety is not a secondary consideration.

Next follows a sub-heading:

"Minimize Dependencies by Storing Members as Pointers"

That's not bad advice, but there is no discussion of the trade-off
involved, notably efficiency.

First paragraph that section then says nothing remarkable, but is
followed by example code that won't compile. It's nothing dramatic (a
missing semicolon) but shows lack of attention to detail.

Then we get to a sub-sub-heading:

"The Initialization List"

and the first sentence of that section

"Note that it is terribly important that you initialize pointer
members (actually any member) of your objects in the constructor's
initialization list."

which is simply false, again. Some times (the FAQ lists some
situations) it's terribly important that you don't.

Third sentence of that section:

"If you don't always need to have a pointer member in existence during
the lifetime of your object, you may choose to initialize it to nil"

'nil' is Pascal terminology, there's no such thing in C++ (the author
probably means 0).

Ah, well, I'm not going to trash that article. As a motivational
article it's great. But as a technical resource it's not up to the
FAQ's standard of quality -- not even 10% in that direction.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jan 29 '06 #16

P: n/a
On Sun, 29 Jan 2006 02:04:15 GMT, al***@start.no (Alf P. Steinbach)
wrote:
* JustBoo:
Also the FAQ has a pretty bad article about it.
http://www.parashift.com/c++-faq-lit....html#faq-10.6
Much Much Much Better Here:
http://www.goingware.com/tips/parame...embervars.html


This article is sometimes misleading and incorrect.

[snipped commentary]

Thank you Alf, for all that work.

Note I included *both* links. I find comparative analyses to be an
invaluable tool for a software engineer.

Also note, I now realize I should have tempered *my commentary* about
the articles themselves.

I have to say thought, I'm glad we're all just commentators on usenet
and not editors. :-) <==

Success is not final, failure is not fatal: it is the courage to
continue that counts. - Winston Churchill
Jan 29 '06 #17

P: n/a
Responding to Daniel T. and Whoever...
The following is a message I came across on comp.lang.c++, it sounded
like a good topic of discussion for comp.object as well, so I'm
forwarding it here...

========== Begin Forwarded Message ==========
From: "Chocawok" <no****@nospam.com>
Subject: tightly coupled class design problem
Date: Fri, Jan 27, 2006 6:11 PM

Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

Given that C++ has reference pointers, I am afraid I not keen on this
and your first sentence. The sprite is a graphical representation /of/
whatever entity MyClass abstracts from the problem space. That
qualifies the sprite as a distinct conceptual entity that is a peer of
MyClass.

So it shouldn't be part of the implementation of MyClass and one needs a
reference based relationship implementation for it. If one thinks of it
as a peer via

1 corresponds to 1
[MyClass] --------------------- [Sprite]

then

Sprite* this_objects_sprite;

just implements the peer relationship. That segues to...
The sprite class requires a pointer to a "video surface". There is no
way
around this. The pointer is required for the construction and drawing of
the
sprite object.
Fine. All the more reason to make Sprite a peer object.
My problem is this:

This design means that I have to pass the pointer to the video surface
to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface*
s);

...

...

}

...

...

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.


I don't see a problem here so long as this_objects_sprite is just
instantiating a relationship. As you indicate above, that relationship
is fixed in the problem space. Therefore it must be established somehow.

If the relationship is fixed throughout the like of MyClass, then
instantiating the reference via the MyClass constructor is fine. If the
context can change during MyClass' life cycle, then one would need a
set_sprite method to re-instantiate the relationship properly when the
context changes.

[Note that even if it is fixed for life now, one can add set_sprite
later if things change with minimal hassle because it /is/ just a
relationship implementation rather than part of the MyClass
implementation. This becomes even more important if one later decides
that [Sprite] needs to be accessed by other objects than {MyClass].
Keep this in mind in the discussion of relationship path navigation below.]

However, the key issue is that relationship navigation is orthogonal to
class semantics. MyClass may or may not need to collaborate with the
Sprite. Assuming MyClass has some other role in solving the customer's
problem, Sprite will probably be accessed by some other object that
understands graphical issues like when the display needs to be rendered
or updated. So it is likely that Sprite will be accessed /through/
MyClass by that object and MyClass won't know anything about that, as in:

[Renderer]
| 1
| displayed by
|
| R1
|
| *
[MyClass]
| 1
| corresponds to
|
| R2
|
| 1 * constrains 1
[Sprite] ------------------------ [VideoSurface]
R3

To do the display Renderer needs the the information from [Sprite] so it
navigates R1 -> R2 to get it. In doing so MyClass is just a way point
in addressing the collaboration to the right [Sprite] instance. Since
Renderer's collaboration is peer-to-peer with Sprite, it doesn't need to
know and shouldn't know anything about the semantics of MyClass (other
than the implementation of the relationship path).

Similarly, if Renderer needs to collaborate with the relevant
VideoSurface, then it also needs to navigate R1 -> R2 -> R3. But in
that peer-to-peer collaboration Renderer needs to know nothing about
MyClass or Sprite. More important to your concern here is that MyClass
doesn't need to know anything about that collaboration or the semantics
of [VideoSurface]. It's only knowledge of [VideoSurface] is the Class
type for C++ to properly type the reference pointer that implements the
relationship.

[Automatic code generators for OOA models don't even need to know the
class. Typically they instantiate relationships with Object*
references. The only place the class type /needs/ to be defined is in
Renderer so it can access properties. The code generator can cast that
safely because it knows from the UML model exactly what the class /must/
be when it write the [Renderer] code.]

So if all one is doing is instantiating a relationship, then there is no
heavy duty coupling between [VideoSurface] and any class along the path
except [Renderer]. (Renderer is necessarily coupled because it is doing
peer-to-peer collaboration with [VideoSurface].) In fact, I believe
that the main role of relationships in the OO paradigm is to provide a
context-independent mechanism to /ensure/ decoupling except among
collaborating peers. [Almost as important is the management of access
to state variables (attributes).]
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hs*@pathfindermda.com
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
(888)OOA-PATH

Jan 29 '06 #18

P: n/a
In article <XI*********************@fe3.news.blueyonder.co.uk >,
"Chocawok" <no****@nospam.com> wrote:
I think I have come to a decision.

I think the best solution is to have a Sprite class which handles the
graphics and drawing of itself.

BUT, and this is the new bit, construct the Sprite outside of the container
object. This way the containing object doesn't need to know ANY details of
how the sprite is constructed or how it draws iself.

e.g.

Sprite
{
bitmap i;
VideoSurface* drawingdestination;
Sprite(VideoSurface* s, bitmap b) { drawingdestination = s; i = b}
Draw();
}

MyClass
{
Sprite* s;
void MyClass();
void AttachSprite(Sprite* s) {this.s = s};
void Draw() {s.draw();}
}

main()
{
myobj = new MyClass();
myobj.AttachSprite(new Sprite(videoram, image));
myobj.Draw();
}

This means all the graphics details (DirectX or OpenGL or GDI etc) stay in
the one class, providing nice encapsulation.


Not quite, but good enough. Presumably, there will be some graphics
details in sprite.h and myclass.cpp must include sprite.h to compile
which means that some of the details will leak into myclass.cpp (at the
very least, if those details change, myclass.cpp will have to be
recompiled.)

This isn't necessarily a bad thing, but it might be better to have an
abstract "Drawable" class that Sprite inherits from and MyClass
contains.

--
Magic depends on tradition and belief. It does not welcome observation,
nor does it profit by experiment. On the other hand, science is based
on experience; it is open to correction by observation and experiment.
Jan 29 '06 #19

P: n/a

Daniel T. wrote:
The following is a message I came across on comp.lang.c++, it sounded
like a good topic of discussion for comp.object as well, so I'm
forwarding it here...

========== Begin Forwarded Message ==========
From: "Chocawok" <no****@nospam.com>
Subject: tightly coupled class design problem
Date: Fri, Jan 27, 2006 6:11 PM

Some of the classes in my app are graphical.

To encapsulate the graphical side of things I had created a class called
"sprite" which holds a bit map and knows how to draw itself etc.

The classes that are graphical contain a sprite object.

MyClass

{

private:

Sprite this_objects_sprite;

}

The sprite class requires a pointer to a "video surface". There is no
way
around this. The pointer is required for the construction and drawing of
the
sprite object.

My problem is this:

This design means that I have to pass the pointer to the video surface
to
myclass in its constructor, e.g.

MyClass

{

private:

Sprite this_objects_sprite;

public:

MyClass(VideoSurface* s)

{

this_objects_sprite = new Sprite(VideoSurface*
s);

...

...

}

...

...

}

Obviously this means all my graphical objects are tightly coupled to the
graphics system I am using. Also obviously (I think) is that this is
undesireable.

I was thinking of maybe arranging things so that the sprite is not
automatically instantiated in the container objects constructor.

That is, I construct my object THEN call a function to construct the
objects
sprite, e.g.

MyClass c = new MyClass();

c.CreateSprite(VideoSurface* s);

But then this raised other issues like, how do I handle what happens if
i
try to draw the object before creating its sprite.

Any thoughts on this?

Dean


sounds virtually exacltly the same scenario described in Design
Patterns (Gamma et al), for the application of the 'abstract factory'
patterm....i.e. basically you abstract away your graphics systems
behind a factory and a family of wrapped.

Have you got GoF?

I could ramble away like an idiot but best look there. p87.

Jan 30 '06 #20

This discussion thread is closed

Replies have been disabled for this discussion.