473,386 Members | 1,598 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,386 software developers and data experts.

tightly coupled class design problem



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
19 2488

"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
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
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

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
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
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
"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
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
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
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
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
> 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
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
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
* 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
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
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
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

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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Veriblue | last post by:
Hello: I am using .NET Enterprise Services (COM+) Loosely Coupled Events (Transient Subscriptions Model) to come up with an Event Model using .NET and C#. The COM+ LCE is exactly what I was...
1
by: yan | last post by:
Hi, everybody. I'm new to this great forum, so hello! I start with a problem of my project. I have an Abstract Base Class used as base class for differentes Derived classes. The derived classes...
3
by: Jack | last post by:
Dear all, I'm using a commercial library that I cannot modify. There's this one class in the library which is almost 90% usable. But unfortunately, I have to reimplement 3 member functions. The...
21
by: Mark Broadbent | last post by:
Consider the following statements //------- Item i = Basket.Items; //indexer is used to return instance of class Item Basket.Items.Remove(); //method on class item is fired item i = new...
3
by: Trammel | last post by:
Hi, I recently upgraded to VB.net from VB6.. and woah... I feel lost :¬O One of my reasons for upgrading is I was told that VB.net can do class inheritance and subclassing easier. ...
5
by: Tony Johansson | last post by:
Hello! I have one solution file that consist of three project. One project that build the exe file called A One project that build a user control dll. Here we have a class called B One project...
0
by: tony | last post by:
Hello! This is a rather long mail but it's a very interesting one. I hope you read it. I have tried several times to get an answer to this mail but I have not get any answer saying something...
2
by: Jim Langston | last post by:
I am working on a class design to contain the indices of triangle lists for body parts. This is for 3d modeling. As as start I have: class PartTriangles { public: PartTriangels( const...
6
by: Bhawna | last post by:
I am into c++ code maintenance for last 3-4 years but recently I am put into design phase of a new project. Being a small comapany I dont have enough guidance from seniors. Currently I am into a...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
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: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
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:
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
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
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...

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.