|
Makes sense.
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
It's an interesting one to say the least. One of the principals of OO development is that you shouldn't return an object out of a constructor that requires further configuration to be useful*. In other words, you shouldn't need to set additional properties before the class is useful. In this particular case, the fact that you can get to the Launch code without setting it, and the first point that you notice that there's a failure is at this point would indicate that the Booster should have been applied earlier on.
*Now, looking at your sample, it would seem that what you are looking at here is an object that would typically be composed using Dependency Injection, so it would be reasonable to assume that the DI code would actually compose your object for you. This would mean that you would be exposing a dependency that your code was reliant on - and this is where it gets slightly murkier. If you favour the wide constructor approach to composition, then every time you need to add an extra dependency to your class, you have to add it to your constructor, and add a backing field for that type. You may prefer the dependency property (I'm not using this in the WPF way here) approach, which means that you would expose a property for it - and this could be an auto property so you wouldn't need to add the field yourself as the compiler takes care of this for you behind the scenes.
|
|
|
|
|
Using the analogy of the rocket, you can still perform a lot of actions - giro tests, etc - without a booster. The booster is an added item, not necessarily an intrinsic part. If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.
Panic, Chaos, Destruction. My work here is done.
Drink. Get drunk. Fall over - P O'H
OK, I will win to day or my name isn't Ethel Crudacre! - DD Ethel Crudacre
I cannot live by bread alone. Bacon and ketchup are needed as well. - Trollslayer
Have a bit more patience with newbies. Of course some of them act dumb - they're often *students*, for heaven's sake - Terry Pratchett
|
|
|
|
|
Nagy Vilmos wrote: If the rocket must have a booster, then I agree it must be a part of the
constructor to ensure its presence.
And that's the rub. What constitues a valid instance of the class? In the admittedly contrived example given, the only operation that could be performed was a Launch, so the booster is an intrinsic part of this particular example.
Now, if this class were one I was designing, I would take a slightly different approach if this was a full lifecycle of a rocket. This particular rocket implementation is tightly coupled to a single booster. What happens if I want a rocket with more than one booster? Or I want to use one that's based on the ACME Fusion Drive 3000 elastic band? To that end, I'd consider that a design like this might be better:
public class Rocket
{
public Rocket()
{
}
public void PreLaunchTests()
{
OnPreLaunchTests();
}
public void Launch()
{
}
protected virtual void OnPreLaunchTests()
{
}
protected virtual void OnLaunch()
{
}
}
public class SingleBoosterRocket : Rocket
{
public List<IBooster> Boosters { get; private set; }
public SingleBoosterRocket()
{
Boosters = new List<IBooster>();
}
public void AddBooster(IBooster booster)
{
Boosters.Add(booster);
}
protected override void OnPreLaunchTests()
{
}
protected override void OnLaunch()
{
if (Boosters.Count == 0)
throw new NotEnoughBoostersException();
}
}
public class DualBoosterRocket : SingleBoosterRocket
{
public DualBoosterRocket() : base()
{
}
protected override void OnPreLaunchTests()
{
}
protected override void OnLaunch()
{
if (Boosters.Count < 2)
throw new NotEnoughBoostersException();
}
} Again, this is a completely fabricated design, but this has the advantage of being more flexible. Ultimately, the design should be based on the real requirements, which is why I have steered well clear of saying that one approach is better than another in all cases. BTW - in case you're wondering, the actual composition in this sample has been moved to the containing object, rather than the actual rocket implementation, as that piece of code would be the one that decided what the composition entailed. The rules for the rocket have been encapsulated in a simple classes that have a single responsibility.
|
|
|
|
|
Thanks for the example Pete
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
|
As Pete says, a constructor should always return a valid object, that is, you should be able to use it in normal situations. So the answer to the question depends on whether a Rocket can be useful without a Booster. In your simplistic example, where it has one method and that method throws an exception if it isn't set, it clearly can't, and therefore the Booster should be assigned in the constructor (and, if applicable, a null check applied there).
|
|
|
|
|
Neither. Rocket should be able to call a factory method "Boosters.GetBooster()", or some other suitable mechanism to acquire what it needs, when it needs it.
Marc
|
|
|
|
|
Funnily enough, that was the gist of the answer that I've just added above.
|
|
|
|
|
Pete O'Hanlon wrote: Funnily enough, that was the gist of the answer that I've just added above.
I read it, but your response was too wordy for me to figure out what you were saying! But none-the-less, two great minds, a single thought between them, eh?
Dependency Injection, hmmm... it's really weird to me how we have these (what I consider to be) massive frameworks to support DI when all it really needs is a simple instantiation engine.
Anyways, I'm getting distracted by the lure of an unoccupied soapbox.
Marc
|
|
|
|
|
We internally have a DI engine that is only 60 lines or so of code, and it's good enough for our purposes when all we need is basic DI.
|
|
|
|
|
Pete O'Hanlon wrote: We internally have a DI engine that is only 60 lines or so of code
Sweet!
Marc
|
|
|
|
|
I think we can think about two scenarios:
1. First, On the ground, we "build" the rocket with boosters and make a launch.
2. We don't build or assemble a rocket, but when a launch is called, it acquires a booster and executes a launch.
The second one is loosely tied.
The Boosters.GetBooster() can be applied for both the scenarios?
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
VuNic wrote: The Boosters.GetBooster() can be applied for both the scenarios?
I think so. In the first scenario, the constructor can call GetBooster to get a concrete instance, though I think it would be much more preferable for Rocket to have a Build() method.
In the second scenario, and this may be over the top, consider that we know that a rocket, among other things, has some form of propulsion mechanism, otherwise it wouldn't be a rocket. Now, a rocket might have a main engine, boosters, stages, ion engines, so forth, a whole slew of combinations of things. So if rocket is to have a "has a" relationship to booster, the concept of booster needs to be abstracted to "propulsion systems", ideally a collection of this abstraction type. The GetBooster factory might return a collection specific to the rocket's requirements. You can define specific collections as a concrete type (there's most likely a limited, well defined set of configurations). Each type (the configuration of propulsion systems) probably has specific launch behaviors. Therefore, the type itself contains all the logic for how to proceed with a launch, going from main engine firing, booster firing, stages, and final orbit maneuverings with ion engines. So, why should the rocket itself know how to do this? The rocket is just a container for a particular configuration. Maybe the rocket performs some coordination with other systems, but the execution of the launch should be delegated to the configuration type.
Which is where functional programming can be used, not only for "computing" the launch, but also for ensuring that configurations, using discriminated unions, are permitted.
Marc
|
|
|
|
|
Hmm as I understand, the design decision completely relies on the exact requirement. More thinking is required to realize what is the system about. The more we are precise with the actual system, the better and sensible design we could make. Thanks for the inputs Marc. All learning for me
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
This is probably a really basic database design question, but for some reason, I'm struggling with it.
The real world problem I'm trying to solve is a little too escoteric to describe, so I'll try to use a generic example that presents the same problem.
Say a store sells two kinds of cogs. Each type of cog is represented in the database with its own table (they have sufficiently different characteristics to warent different table schemas). A customer can buy both kinds of cogs, and we want to keep track of their purchases. So we have a sales table that's associates the customer with the cogs he/she buys. One foreign key points to the customer, and another foreign points to the cog.
What's got me stumped is that the foreign key that points to the cog could be associated with either type of cogs. How do we know which? Do we create an additional field that tells us the type of cog the customer purchased? That rings alarms for me in that it's surely unnormalized.
So instead do we have seperate sales table for each type of cog? But wouldn't this lead to an explosion of tables as we add more cogs types to our inventory?
This must seem like a beginner's question; I'm an old C++ audio programmer who's become a 'web developer', so occasionally I get stumped on DB basics. Any help is appreciated.
|
|
|
|
|
You need to find a way of describing n widgets from a single table so that the problem of new widgets does not require more tables which means a nightmare in maintenance and changing application pages that add, edit and display the data. Even if you can break it down to tables of classes of widgets you might be able to have a widget type table that keys into a widget class table. Even then you may find that you need to add new widget classes to cope but if you can make the table columns generic enough this may not be an issue. Just a quick thought.
"If you think it's expensive to hire a professional to do the job, wait until you hire an amateur." Red Adair.
nils illegitimus carborundum
me, me, me
|
|
|
|
|
Thanks for your reply.
The solution I've settled on uses part of your answer. I have a 'base' table for all items. Then I have tables where needed for 'derived' sub types. These derived tables have a 'zero to one' relationship to the base table. The derived tables are a way of extending the properties of items in the base table.
So the items table could look like this:
+----+--------+-------+
| id | name | price |
+----+--------+-------+
| 1 | wheel | $1.23 |
+----+--------+-------+
| 2 | wire | $1.50 |
+----+--------+-------+
Then if there are more than one kind of cogs, I can subclass them in 'derived' tables (like derived classes in object oriented programming).
wheels table
+----+--------+--------+
| id | cog_id | radius |
+----+--------+--------+
| 1 | 1 | 50" |
+----+--------+--------+
wires table
+----+--------+--------+
| id | cog_id | length |
+----+--------+--------+
| 1 | 2 | 12" |
+----+--------+--------+
I can then do joins to get back only wheels, and another join to get just wires.
I'm not sure if this is a common approach. I know the joins will cost more processing, but at least the schema makes sense to me.
|
|
|
|
|
Leslie Sanford wrote: I'm not sure if this is a common approach.
It is. And it's one that I strongly prefer over a solution where one "extends" the record by linking to a table with "custom fields" (most often key/value pairs of strings).
Leslie Sanford wrote: I know the joins will cost more processing, but at least the schema makes sense to me.
..just a little extra overhead. Other alternatives would only make it worse, you'd end up with a lot of empty fields or with weird join-constructions.
Bastard Programmer from Hell
|
|
|
|
|
Leslie Sanford wrote: (they have sufficiently different characteristics
How are thos charactistics used?
In the right situation you can use a meta-data solution to represent the additional attributes.
|
|
|
|
|
today I discuss with my friends .we conculde that there is two ways design base class .
1 .we design the method whether belongs to all class or only belongs to sub-class into base-class
the code writed like that
class CVehicle
{
public:
virtual void fly()
{
cout<<"I'm sorry I don't have method fly"<<endl;
}
virtual void Ride()
{
cout<<"I'm sorry I don't have method Ride"<<endl;
}
virtual void Run()
{
cout<<"I'm sorry I don't have method Run"<<endl;
}
};
class CAeroplane:public CVehicle
{
public:
void fly()
{
cout<<"I am a Aeroplane i can fly "<<endl;
}
};
class CBike:public CVehicle
{
public:
void Ride()
{
cout<<"I am a Bike i can Ride "<<endl;
}
};
class CCar:public CVehicle
{
public:
void Run()
{
cout<<"I am a Car i can Run "<<endl;
}
};
2 .we think that sub class has its own method so we should design like that
class CVehicle
{
public:
};
class CAeroplane:public CVehicle
{
public:
void fly()
{
cout<<"I am a Aeroplane i can fly "<<endl;
}
};
class CBike:public CVehicle
{
public:
void Ride()
{
cout<<"I am a Bike i can Ride "<<endl;
}
};
class CCar:public CVehicle
{
public:
void Run()
{
cout<<"I am a Car i can Run "<<endl;
}
};
so which way will the best way we should order ?
|
|
|
|
|
wan.rui@qq.com wrote: so which way will the best way we should order ?
2.
A base class should only contain members that are common to those which will derive it.
Signature construction in progress. Sorry for the inconvenience.
|
|
|
|
|
The answer is neither. The aim of the base class should be to encapsulate operations that are common to all derived classes. In your first example, having the ability to fly makes no sense in the case of a class like CBike unless you are modelling scenes out of ET. In your second example, there's no reason to have a base class at all (btw, people run, car's don't). A better example would be:
class CVehicle
{
public:
virtual void Move();
}
class CCar: public CVehicle
{
public:
void Move()
{
cout << "I am a car. I can be driven" << endl;
}
}
class CBike: public CVehicle
{
public:
void Move()
{
cout << "I am a bike. I can be ridden" << endl;
}
}
class CAeroplane: public CVehicle
{
public:
void Move()
{
cout << "I am an aeroplane. I can be flown" << endl;
}
}
|
|
|
|
|
I mean there are some different action in different subclass ,where i can't conclude a common interface like move() .
my question is when we at this situation we write all different method in base class?or put the different method in different sub-class?
|
|
|
|
|
If you can't ask a common question, how can you interact with the base class? Answer: you can't. If you want something to move, no further questions asked, provide a move() method (possibly abstract/pure virtual) and override it to do the actual movement in subclasses. If you need to know the type of something before asking it the question, then you're probably asking the wrong question.
|
|
|
|
|