473,748 Members | 4,065 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Class design (again)

nw
Hi,

I previously posted a question asking for suggestions on my class
design. My original code consisted of a pure virtual base class Body
which contained a number of integration algorithms which are applied
to the Body. Generally only one integration algorithm is used via an
integrate() method, which selected the integration algorithm to call
depending on a variable.

Code similar to the following was suggested as a improvement. I have
modified it so it should compile on gcc. In the posters example
acceleration had also been moved from Body to Integrator, in the wider
context of my code I don't think I can do this. Here is the new class
design:

#include <iostream>
#include <ostream>

using namespace std;

class Body;
class IntegratorImpl;

class Integrator {
public:

Integrator() {}
~Integrator() {}

enum IntegratorType
{
kNone, kEuler, kVerlet, kLeapFrog
};

bool integrate();
void selectIntegrato r(IntegratorTyp e t, Body &b);

private:
IntegratorImpl *m_impl;
};

class Body
{
public:
Body() {}

bool integrate() { return m_integrator.in tegrate(); }

void selectIntegrato r( Integrator::Int egratorType type )
{
m_integrator.se lectIntegrator( type, *this );
}

Integrator m_integrator;
double position_x, position_y, position_z;
double velocity_x, velocity_y, velocity_z;
double acceleration_x, acceleration_y, acceleration_z;
static const double dt = 1;
};

class IntegratorImpl {
public:
IntegratorImpl( Body &b) : m_body( &b ) {}

virtual bool integrate() = 0;

protected:
Body *m_body;
};
class EulerIntegrator : public IntegratorImpl {
public:
EulerIntegrator (Body &m_body) : IntegratorImpl( m_body) {}

bool integrate() {
// do Euler integration
m_body->velocity_x += m_body->acceleration _x * m_body->dt;
m_body->position_x += m_body->velocity_x * m_body->dt;
// etc...
cout << "Euler integration called" << endl;
return true;
}
};

class VerletIntegrato r : public IntegratorImpl {
public:
VerletIntegrato r(Body &m_body) : IntegratorImpl( m_body) {}

bool integrate() {
// do Verlet integration
// etc...
cout << "Verlet integration called" << endl;
return true;
}
};

// Class LeapfrogIntegra tor similar to EulerIntegrator not shown

void Integrator::sel ectIntegrator(I ntegratorType type,Body &body) {
switch( type ) {
case kEuler:
m_impl = new EulerIntegrator (body);
break;
case kVerlet:
m_impl = new VerletIntegrato r(body);
break;
default:
// throw? your choice
break;
}
}
bool Integrator::int egrate() {
return m_impl->integrate();
}

class Planet : public Body {
public:
Planet() {}

double calcForce(Plane t &p)
{
acceleration_x = (p.position_x - position_x) * (p.position_x -
position_x);
}
};

// Class SimpleHarmonic, not shown defined similar to Planet

int main() {
Planet p;
Planet p2;
// SimpleHarmonic s;

p.selectIntegra tor( Integrator::kEu ler );
p2.selectIntegr ator( Integrator::kVe rlet );
// s.selectIntegra tor( Integrator::kLe apfrog );

cout << "planet,eul er: ";
p.integrate();

cout << "planet,ver let: ";
p2.integrate();

// cout << "simpleharmonic ,leapfrog: ";
// s.integrate();

return 0;
}

In this code an Integrator object is stored by Body, Integrator is
provided with a reference to Body which it uses to access the data
from Body it needs to perform the integration (this should probably be
encapsulated better than it is in the example code) and a value
specifying which type of integrator to use. The Integrator object
creates an IntergratorImpl object depending on this type. And when
Integrator.inte grate() is called, the call is passed on to the
underlying implementation.

I believe this is an improvement over my original code but that this
solution would construct lots of largely empty integrator objects,
which only contain a pointer to Body. Is it possible to avoid this?
And also perhaps the overhead caused by the Integrator object? Are
there other solutions I should consider?

The previous posters, and any additional advice is appreciated.

The original thread is here:

http://groups.google.ie/group/comp.l...03c8ebcd5cbe9d

Feb 22 '07 #1
2 1797
nw wrote:
>
I believe this is an improvement over my original code but that this
solution would construct lots of largely empty integrator objects,
which only contain a pointer to Body. Is it possible to avoid this?
And also perhaps the overhead caused by the Integrator object? Are
there other solutions I should consider?
It's good to see you've adapted my original suggestion to you. What
you have just implemented is a Strategy Pattern. It is generally a
good idea to keep it the way you implemented. As for instancing largely
empty objects, these empty objects by design help you mix and match
different integration methods without impacting the API that much. This
means, creating a different integration method will not propagate
a lot of code change outside the Strategy pattern. Also, as you have
noticed, your old switch statement is replaced by the virtual integrate
calls thus keeping your code cleaner. So not unless there is a need
to keep memory to a very minimum, I highly recommend to keep it that
way since you are trading off future extensibility and maintainability
of your code if you remove it. The run-time performance should also not
be that big of an issue since the majority of your time should be spent
on integrating anyway so the overhead of a pointer indirection and
a virtual call should be tiny.

If you insist on redesigning it, you can first remove Integrator and
use IntegratorImpl directly inside your Planet. This removes a memory
overhead. You can also then also remove IntegratorImpl and make each
Integration object a Functor (this removes the virtual call overhead).
Then you can use boost::function to make your signatures cleaner and
then you can pass in the functor object at run-time.
(example code at the bottom)

Good Luck with your project!

PS. please please please consider getting boost. I noticed you chose
not to use it. It makes life easier.

Note: this is not complete compilable code. For illustration
purposes only.
---------------------------------------------------------------
#include <boost/function.hpp>

class EulerIntegrator
{
public:
// do what you need to construct it properly
EulerIntegrator ();
bool operator()( Body * b )
{
// do Euler Integration
}
};

// same for other integrators

class Planet : public Body // you know how to define Body already
{
public:
// instead of selecting an integrator with a token, you can
// pass a functor to the integrator object directly.
bool integrate( boost::function <bool (Body*)f )
{
// I am assuming that the body you want to integrate
// with is itself.
return f( this );
}
};
int
main(void)
{
Planet p;
p.integrate( EulerIntegrator () );
}
Feb 22 '07 #2
Code similar to the following was suggested as a improvement. I have
modified it so it should compile on gcc. In the posters example
acceleration had also been moved from Body to Integrator, in the wider
context of my code I don't think I can do this. Here is the new class
design:
<excerpts follow>
class Integrator {
public:
bool integrate();
void selectIntegrato r(IntegratorTyp e t, Body &b);

private:
IntegratorImpl *m_impl;

};

class Body
{
public:
bool integrate() { return m_integrator.in tegrate(); }

void selectIntegrato r( Integrator::Int egratorType type )
{
m_integrator.se lectIntegrator( type, *this );
}
};

class IntegratorImpl {
public:
IntegratorImpl( Body &b) : m_body( &b ) {}

virtual bool integrate() = 0;

protected:
Body *m_body;

};

class EulerIntegrator : public IntegratorImpl {
public:
EulerIntegrator (Body &m_body) : IntegratorImpl( m_body) {}

bool integrate() {
// do Euler integration
m_body->velocity_x += m_body->acceleration _x * m_body->dt;
m_body->position_x += m_body->velocity_x * m_body->dt;
// etc...
cout << "Euler integration called" << endl;
return true;
}

};
I believe this is an improvement over my original code but that this
solution would construct lots of largely empty integrator objects,
which only contain a pointer to Body. Is it possible to avoid this?
And also perhaps the overhead caused by the Integrator object? Are
there other solutions I should consider?
I would suggest you change this:
IntegratorImpl( Body &b) : m_body( &b ) {}
virtual bool integrate() = 0;

To
IntegratorImpl( ) {}
virtual bool integrate(Body& b) = 0;

Right now, your IntegratorImpl has 2 responsibilitie s:
1) Store Body
2) Implement integration strategy

My suggestion is to get rid of responsibility 1. (OO guideline -
classes should have exactly 1 responsibility. Not always 100% true,
but a good guideline.)

Once you have done that, then you don't need to allocate a new
strategy object each time you set the integration strategy - instead
you can implement your various strategies as Singletons, and just
store a pointer to each in the selectIntegrato r method (note: you
would not own that pointer, so you shouldn't delete it). That way, if
you have 5 strategies and 1000 bodies, you would only have 5 strategy
objects, not 1000.

Michael

Feb 22 '07 #3

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

Similar topics

1
2270
by: Alfonso Morra | last post by:
if I have a class template declared as ff: (BTW is this a partial specialization? - I think it is) template <typename T1, myenum_1 e1=OK, my_enum_2=NONE> class A { public: A(); virtual ~A() ;
9
1469
by: Sacha | last post by:
I work on a rather large C++ project. The design, so far, seems to be fine. However, there is one class, where the number of methods (and less dramtically the number of members, too) is growing and growing. I thought of different strategies to divert the glut into 'different functional units', like * through inheritance * using member objects to encapsulate the methods of the parent object * split the class without a parent class *...
7
3479
by: Dan Trowbridge | last post by:
He everyone, I am just getting started with .NET and I am having a porting problem. I get and error in code that lookssomething like this (really stripped down but you get the idea)... class dt { std::deque< class dt > dtdq; };
6
2116
by: rodchar | last post by:
Hey all, I'm trying to understand Master/Detail concepts in VB.NET. If I do a data adapter fill for both customer and orders from Northwind where should that dataset live? What client is responsible for instantiating the orders class? Would it be the ui layer or the master class in the business layer? thanks,
15
2418
by: Joe Fallon | last post by:
I would like to know how you can figure out how much memory a given instance of a class is using. For example, if I load a collection class with 10 items it might use 1KB, and if I load it with 1000 items it might use 100KB. How do I measure the amount of memory used once the class is loaded? Thanks! -- Joe Fallon
0
3935
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 like this is a bug or that .NET doesn't support what I trying to do. I hope that one that is is microsoft certified read this because this must be a bug.
5
3077
by: Joe Van Dyk | last post by:
Say I have the following class: using std::string; class Player { public: Player() : name(""), age(""), other_stuff("") {} private: string name; string age;
6
2078
by: Orgun | last post by:
Hi, I sent this message to the moderated c++ group too but it is waiting for moderator approval and I wanted to send here too. I am new to Design Patterns. I want to write a simple DeviceManager which is only interested in CD/DVD devices. I want to get the list of CD/DVD devices and "be informed when a disc inserted into a device". I am developing this on Linux. So, I used HAL API and read some system (actually /proc) files to gather...
26
5373
by: nyathancha | last post by:
Hi, How Do I create an instance of a derived class from an instance of a base class, essentially wrapping up an existing base class with some additional functionality. The reason I need this is because I am not always able to control/create all the different constructors the base class has. My problem can be described in code as follows ... /* This is the base class with a whole heap of constructors/functionality*/ public class Animal
12
6133
by: Gordon | last post by:
I want to provide a set of static functions in a superclass that work with class constants defined in a decendant of that class. Unfortunately I've run into a snag with this idea. Example: class SuperClass { const CNST = 'Super class'; public static function getCnst () {
0
8987
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9366
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9241
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8239
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6793
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 presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4597
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4867
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3303
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2777
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.