|
Hello ,
While I use a different coding platform, I've worked a bit with inheritance and client/server applications. The examples described below is pseudocode (okay, I lie, it's a hack of mostly Delphi mixed with pseudocode, so sue me :P), so you should be able to make a decision as to whether you would want to use inheritance or not.
Your particular scenario involves transporting data between a client and a server. What data is being transported (for argument's sake) isn't actually what's important, how you *interpret* the data, on either side of the protocol, is. The core functionality of your base class involves just putting the data into a stream and reading the data from a stream. Nothing else. You don't want your objects to do more than it needs to. The specialisation of each (derived) class will contain the specific enhancements that you would want from it. So for my example, you have your class defined like so:
TYourBase = class(TObject)
protected
procedure WriteToStream(AStream : TMemoryStream); virtual;
procedure ReadFromStream(AStream : TMemoryStream); virtual;
public
function ToStream : TMemoryStream;
procedure FromStream(AStream : TMemoryStream);
end;
With your implementation for this class looking something like this:
procedure TYourBase.WriteToStream(AStream : TMemoryStream);
begin
end;
procedure TYourBase.ReadFromStream(AStream : TMemoryStream);
begin
end;
function TYourBase.ToStream : TMemoryStream;
begin
Result := TMemoryStream.Create;
WriteToStream(Result);
end;
procedure TYourBase.FromStream(AStream : TMemoryStream);
begin
ReadFromStream(AStream);
end;
Now for the inheritance part. Let's say that your derived class needs to contain a few accessors (a string, an integer and a float). You would define it something like this:
TSomeDescendant = class(TYourBase)
protected
procedure WriteToStream(AStream : TMemoryStream); override;
procedure ReadFromStream(AStream : TMemoryStream); override;
public
SomeString : String;
SomeInteger : Integer;
SomeFloat : Real;
end;
With the implementation looking something like this:
procedure TSomeDescendant.WriteToStream(AStream : TMemoryStream);
begin
inherited WriteToStream(AStream);
AStream.WriteString(SomeString);
AStream.WriteInteger(SomeInteger);
AStream.WriteFloat(SomeFloat);
end;
procedure TSomeDescendant.ReadFromStream(AStream : TMemoryStream);
begin
inherited ReadFromStream(AStream);
SomeString := AStream.ReadString;
SomeInteger := AStream.ReadInteger;
SomeFloat := AStream.ReadFloat;
end;
Now, when you want to read or write from a stream, all you will need to do is something like this:
var
LSomeObject : TSomeDescendant;
LStream : TMemoryStream;
begin
LSomeObject := TSomeDescendant.Create;
LSomeObject.SomeString := 'test';
LSomeObject.SomeInteger := 1;
LSomeObject.SomeFloat := 5.5;
LStream := LSomeObject.ToStream;
FreeAndNil(LSomeObject);
LSomeObject := TSomeDescendant.Create;
LSomeObject.FromStream(LStream);
end;
This is just one way in which you can use inheritance to simplify your streaming of data. To put this into an even broader context. You can define virtual methods in your ancestor class(es), to do things like validate the class or anything you want. Bearing in mind your example, you could define a virtual method to persist the data. That way you can define descendants that don't necessarily persist your data to SQL server, it could persist to anything you like: XML, Excel, [insert your favourite persistance flavour here].
I hope this helps you understand a bit more about how inheritance can help you build your class(es) to do as little as it possibly needs to do, while still allowing it to function correctly. By defining virtual and abstract functions and methods, you allow your derived classes to do what it needs to do, specific to itself. Where you define your printer class, you can specifically stream your data for that class. If you define several other classes, you can define specific reading and writing to the stream. This is how you provide polymorphic behaviour to your objects.
My example of writing and reading from a memory stream may not pertain to your example specifically, so I'll leave you with this final story: One of the more classic 'real life' examples of polymorphic behaviour is the question "What makes a saw a saw?". Programmaticaly, If you define a class called TSaw with a (virtual) method called Cut. The TSaw object itself does not know what to do when it needs to Cut. But you can define TRipSaw and THackSaw descendants which overrides the Cut method. They are still both TSaw descendants (and for all intents and purposes, they are still both saws), but they Cut differently. You wouldn't use a THackSaw to Cut wood, nor would you use a TRipSaw to Cut metal, but they both Cut and they are both saws... ...
Okay, I'd better stop this monologue and let you decide from there ...
Cheers,
Glen Vlotman
|
|
|
|
|
Inheritance should be used sparingly in business applications. In reality, in terms of these applications, inheritance has limited value compared to the internals, military, and scientific sectors.
Developers who use inheritance for the most part use it unnecessarily add a lot of ambiguity to the systems they are working on. Nonetheless, there are reasonable situations where inheritance can be of value; the most important being where you have numerous different types of constructs that basically belong within a same set of data (ie: security types; employee types).
That being said here are a few axioms that you should always follow when using inheritance as described by Tom Patton a number of years ago in his second edition of his COM+ Component programming manual:
1) Never use more than three levels of inheritance. Once this rule is broken inheritance hierarchies tend to become too complicated for easy maintenance.
2) Never use a "Protected" access modifier for a variable or method implementation. This attribute has been the bane of many inheritance hierarchies causing
them to fail. The reason being is that they tend to break such hierarchies when updated during maintenance.
3) Test your inheritance hierarchy thoroughly to make sure that it works in all scenarios as expected.
4) Test your inheritance hierarchy for its level of "black-box reuse". The more an inheritance hierarchy can be used without any understanding of anything
but the public API, the more concrete your structure will be. Most inheritance hierarchies tend to fall in the "white-box reuse" range meaning that there
are higher levels of maintenance required, which is not what you want.
5) If you find that your hierarchy is causing more issues than warranted either redesign it or drop the implementation all-together. It will only get worse as
it enters a production mode.
Steve Naidamast
Black Falcon Software, Inc.
blackfalconsoftware@ix.netcom.com
|
|
|
|
|
Err ... I could go a lot about the pros and cons of inheritance and interfaces. Good and bad design is all a matter of taste anyway. Or to put it another way, no two programmers will ever agree. What I will say is it is important to be consistent, at the very least, and if you find you are posed with these types of questions then in all likelyhood you haven't done enough preparation in your design.
I'll point you in the direction of a book called "Head First Design" patterns. It is easy to read and gives you a good understanding of the issues involved in OOP&D. At least, it helped me bridge the gap between structured/procedural programming and OOP.
|
|
|
|
|
Hi mbb01,
I totally agree with you there. In programming we have the gift (or curse - whichever way you look at it) of a plethora of implementations that will provide you with a multitude of solutions to your given scenario. The real test of a good developer is to select the solution/implementation which is not necessarily the 'best' solution, but the one that is the most correct given the tools that you have at your disposal.
What I've found through my years of coding, as I'm sure most of the people here have, is that the solution which usually ends up being used, is a cross between 2 or more methodologies meshed into a symbiotic balance of using the pros from them to the solution's advantage, while mitigating the cons of these methodologies. The bottom line is: there is no "silver bullet".
Wrt books, my poison of choice is "Design Patterns: Elements of Reusable Object-Oriented Software" by TGoF, with ISBN-10: 0201633612 or ISBN-13: 978-0201633610. This book provides a overall approach to understanding in (relatively simple) laymen's terms the bulk of the most popular design patterns that are out there.
Cheers,
Glen Vlotman
|
|
|
|
|
Thanks guys! I really didn't plan any of this to be honest. I was just trying to learn and figure out Sockets. Either way I would like to design a product like the LabTech software I was speaking of, but like you mentioned I should plan it out before trying such a project.
|
|
|
|
|
Jacob, there is nothing wrong with using inheritance. This is one of the pillars of OOD/OOP. Through inheritance, you also get polymorphism, one of the other pillars. You want to use an interface vs. a base class. An interface is a "base class" in theory, but has no definition. Rather it is a contract. The interface you derive your class from says that the derived class will define (host) these methods. A true base class (even abstract base class) holds common methods and data that derived base classes use. Think back to biology, when they discussed about the various classes, species, etc. of plants and animals. We all know that dogs and monkeys are types of mammals. This signifies inheritance, since mammals have certain attributes common to both dogs and monkeys. Then both dogs and monkeys have their differences. (And C# and Java can only have a single base class makes it easier.) The fact that both dogs and monkeys are mammals signifies polymorphism. This also signifies the "is a" relationship. A dog is a mammal. Therefore, the dog inherits traits and attributes (methods and data) from the mammal.
There is also the "has a" relationship where the class contains (encapsulates) a data item. Much like your Commons class contains two Task objects. A dog has four paws instead of hands and feet. Of course, these could be specialized derived objects in the base mammal object.
In the case of your Commons and Printers classes, it can stand as it is, since all it carries is data. If your properties are going to do more processing with the internally stored data, then an interface would be good if you plan to have other ways of holding your Commons data.
The main arguments for using inheritance that I have run up against is the "has a" vs. "is a" relationship. If your class "is of" another class, then use inheritance. If you class contains another class/object, then add that object as a data object.
I have also found that as I create objects/classes, sometimes I find that two or more of the objects have similar methods and data. That is a good place to use inheritance. Take the common methods and data and re-factor them into a base class and have both the old classes inherit from the base class. Also, if I find that I do need to inherit from two or more classes (as back in the old C++ days), see which one is the best choice to inherit from and encapsulate the others.
|
|
|
|
|
|
Hi,
I'm not sure what it is you want, not even what platform you are using: DirectX, XNA, WinForms, ...?
If it is WinForms, you might want and read this little article[^].
FYI: There are quite a number of articles about games here on CodeProject.
|
|
|
|
|
ok sorry, erm... what i want is to scrool the grid as the player moves from the right to the left so that the player can proceed through the level and it isn't all displayed at once
i am using winforms to make my game
|
|
|
|
|
OK, read the article I provided a link to. Then whenever the grid has to move (by user action or timer), change your relevant data values and call Invalidate to get everything repainted.
If everything is linked to a grid, and only part of that is visible, have a Location variable (i.e. a Point with X and Y) that holds the distance from your grid's top left corner to your visible area's top left corner, and offset everything inside your Paint handler by that distance. Graphics.TranslateTransform() could do all that for you.
BTW: if you haven't already, I suggest you make your painting area double-buffered to reduce or avoid flicker.
|
|
|
|
|
|
Please don't delete your questions. Now it's impossible to follow the context of this question, and it could have been something useful to others. You've been a poster long enough to know that you shouldn't be doing this.
|
|
|
|
|
Yes, there already is another guy asking basically the same thing, it is a bit harder now to convince him the subject got handled here.
|
|
|
|
|
how we can make an windows forms with own codes?
tanks!
|
|
|
|
|
Hi,
A bit of a broad answer, but I'm having trouble trying to figure out what you're trying to do, and how.
nasis1 wrote: how we can make an windows forms with own codes?
Using Visual Studio? Start a new project of the type "Windows Application". That should open a new template for a Windows-Application, including a single form that you can edit to your liking.
If you're on a different system, or don't have Visual Studio, you'd create a new project, add the reference to "System.Windows.Forms.dll", add the "using System.Windows.Forms" on top of your file, and then you can declare new forms;
class MyForm: System.Windows.Forms.Form
{
}
static class Program
{
static void Main (String args[])
{
System.Windows.Forms.Application.Run (new MyForm);
}
}
There's a lot of information to be found on MSDN[^], if you scoll halfway the page you'll find some common walkthroughs.
Hope this helps a bit
I are Troll
|
|
|
|
|
The same way you get to Carnegie Hall.
|
|
|
|
|
Take a left at Central Park
I know the language. I've read a book. - _Madmatt
|
|
|
|
|
Or was it 3 rights... I can never remembers...
I wasn't, now I am, then I won't be anymore.
|
|
|
|
|
|
Ba-doom ching! IThankyaw!
|
|
|
|
|
Write your own API and/or framework -- but I don't recommend it, I suggest you use .net instead.
|
|
|
|
|
How we can make a component ?
I want to make a component whit a classlibrary not with usercontorols?
|
|
|
|
|
Simply write something and call it a component.
|
|
|
|
|
|
No, there's no reason to do that; I can create whatever I like and call it a component. I can have an enum that's a component of my Widget facility.
|
|
|
|
|