class within class, design stuff, need expert opinion

N

Nick Valeontis

Hi to all!

I am writing an implentation of the a-star algorithm in c#. My message is
going to be a little bit long, but this is in order to be as specific as
possible. My question has nothing to do with the algorithm. It is related to
OOP in c#.

I have created a class named astar.cs. An instance of the class among other,
contains a instance of a class named Input to store the input parameters of
the algorithm and an instance of a class named Result to store the results
of the algorithm. Here is an example of the final result:

------------------------------------------
CAstar astar = new CAstar();
astar.Input.StartPoint = new Point(0,0);
astar.Input.GoalPoint = new Point(500,500);
astar.Space.Addpolygon(100,100,100,200,200,200,200,100);
astar.Space.Addpolygon(... ... ...);
astar.Solve();
if (astar.Result.Successful) { Console.writeln(astar.Result.ExpandedNodes) .
....};
------------------------------------------

I like the fact that input parameters are not messed with results. Results
as accessed as astar.Results.* and input parameters of the algorithm are
accessed as astar.Input.*

In the example above: Input, Space, Result are classes within the class
CAstar, eg:

------------------------------------------
public class CAStar {
.....public class clsResults {...}
.....public clsResults Results = new clsResults();
------------------------------------------

The CAstar uses events to notify controls (textboxes and panels) when data
are changed. I use handlers to capture those events and update the controls
so that I can view the progress of the algorithm. Here is an example:

------------------------------------------ (in a win form):
astar.ProgressMessageHandlers += new CAStar.StringEventHandler(LogHandler);
(...)
private void LogHandler(Object sender, string e) {txtData.Text += "\r\n" +
e;}
------------------------------------------

In the example above, whenever astar has something to report, it calls the
ProgressMessageHandlers (declared as an event). The LogHandler get the text
sent, and presents it to the screen.

So here is my problem.

If an input parameter is changed after astar.solve() is called ( like:
astar.Input.StartPoint = new Point(0,0); ) I want the data in the textboxes
and graphic panels to be updated. BUT, StartPoint is a member of the class
Input, which does not have access to the events of the astar class (since
astar contains Input and not the other way arround). So I cannot call
ProgressMessageHandlers from within the class Input.

BUT, if I add a property in astar class to set the astar startpoint (a
property thru which I could call ProgressMessageHandlers in set{} section),
I lose the versatility of the syntax: astar.Input.* . I would have to type
astar.SetGoalPoint, astar.SetStartPoint, astarGetExpandedNodes and so on
which leads to a complete chaos of properties.

Is there a way to avoid this? I want like to keep access of input parameters
and results separated but I want CAstar to automatically notify controls to
update their data.

Thanks to all who read all of this. I didn't know how to write all of this
stuff in a more compact way.(!)
 
M

Marc Gravell

How about Input and Results having a reference to the creating CAstar?
If CAstar creates them then this could be as simple as (incomplete
code):

class CAstar {
public CAstar() {
input = new clsInput(this);
results = new clsResults(this);
}
// ...
public class clsInput {
private readonly CAstar star;
public clsInput(CAstar star) {
this.star = star;
}
}
}

If the caller acutally creates the input instance, then you could do
this via a method on CAStar:
class CAstar {
// ...
public clsInput CreateInput() {
return new clsInput(this);
}
}

Either way, this then allows CAstar to have a *private* method e.g.
OnProgressMessageHandlers, which clsInput can then call (for instance
in the property setter) star.OnProgressMessageHandlers({any args
necessary}), since inner classes can call private methods of outer
classes:

public class clsInput {
private string someField;
public string SomeProperty {
get {return someField;}
set {
if(value!=SomeProperty) {
someField = value;
star.OnProgressMessageHandlers();
}
}
}
}

Does this help?

On an unrelated note: it doesn't really matter to the compiler, but it
would probably help your code to read the MS naming conventions
(conventions, not hard rules). For instance, the cls prefix would be
unnecessary. But we know what you mean, so trivial really...

Marc
 
M

Marc Gravell

For reference (also on conventions), the "On{blah}" method is just the
method that fires the event:

public event SomeEventHandler SomeEvent;
private void OnSomeEvent({args}) {
SomeEventHandler handler = SomeEvent;
if(handler!=null) {
handler(this, {args - perhaps creating a SomeEventArgs});
}
}

Also - note that to meet normal convention the StringEventHandler would
have an StringEventArgs : EventArgs which has a string value as a
property. But it should work your way too.

Marc
 
N

Nick Valeontis

Thanks Mark for your quick answer.

I followed your advice and of course it works ok. The code didn't become any
uglier ;-)


Regarding the naming conventions, I tend to add silly prefixes like cls, C
etc, when the classes/variables etc are not to be used anywhere outside one
of my classes. In that way I can group local variables, controls etc in
intellisense. clsResults is a bad example of that logic. This is because
even though new instances of clsResults are only to be created from within
the class astar (clsResults is not to be used anywhere else), clsResults
instance properties are actually accessible outside that class. As the
program becomes bigger and bigger and classes tend to be more independent, I
see that prefixes become more of a problem than an convenience..

Anyway, by googling for MS conventions, I see that many people would agree
or disagree with this.

So ... you have been helpful, thanks again!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top