How will encapsulation help when making changes in code and from its
rippling effects. For a data member, if I change its type from int to
float, (even if I am exposing this using property) I will need to
change variable type where I am using already using this code.
The benefit of encapsulation is that it lets you change the internal implementation without breaking client code. It doesn't protect you if you decide that you need to change the interface to your code, but that's a different matter.
Example: Say you have a value representing the price per unit of some commodity. The price is expressed in cents, and because you don't deal in fractional cents you decided to make the property an integer (I'll use C here because I'm not very familiar with C#):
int _price
int pricePerUnit(void) {
return _price;
}
int priceForUnits(int units) {
return units * _price;
}
That all works out fine until one day when somebody notices that your firm is losing a lot of money due to rounding errors. Many of the commodities that you track are bought and sold in lots of many thousands of units, so you need to start tracking the price to an accuracy of at least 0.001 cent. Because you were smart enough to encapsulate the price instead of letting clients access it directly, you can make that change pretty quickly:
double _dprice
int pricePerUnit(void) {
return (int)_dprice;
}
int priceForUnits(int units) {
return (int)(units * _dprice);
}
The interface that clients use to obtain prices stays the same, but the data they get back is now more accurate. If the price per unit is $1.001, priceForUnits(1000000)
will now return a price that's $1000 greater than before. That happens even though you haven't changed the interface to your system at all, and you therefore haven't broken any client code.
Now, that may not always be all that you need to do. Sometimes you'll need to change or augment your interface so that you can report the price more accurately to clients, too:
double pricePerUnit() {
return _dprice;
}
A change like that will break client code, so you might instead keep the old interface and provide a newer, better routine:
int pricePerUnit() {
return (int)_dprice;
}
double accuratePricePerUnit() {
return _dprice;
}
You and the rest of your team can then embark on the process of converting all the clients of your system to use the newer, better accuratePricePerUnit()
. The client code will get more accurate as you make progress on that task, but even the old stuff should continue to work as well as it did in the past.
Anyway, the point is that encapsulation lets you change the way the internals work while presenting a consistent interface, and that helps you make useful changes without breaking other code. It doesn't always protect you from having to update other code, but it can at least help you do that in a controlled manner.
No, there's no way to change the instantiated type of an object. A Vehicle
is a Vehicle
, and will remain such until it goes out of scope.
Your choices here are threefold:
- Make the type of
Vehicle
simply a property on the Vehicle
object, and default it to Unknown
.
- This works best when there's little functional difference between a
Car
and a Truck
.
- Functions may return different results depending on the
VehicleType
, and you'll need to handle the Unknown
case, but it's trivial to reassign.
- Replace the
Vehicle
with a new object of Car
or Truck
- This would require either a
IsActuallyACar()
method on the Vehicle
which returns a Car
, or a Car
constructor which takes a Vehicle
as an argument (which is the much better choice).
- Going with this method requires you to manually remove the
Vehicle
from everywhere that it's stored, and replace it with the newly created object.
- Rethink your design so that
Vehicle
is abstract and you don't create the object until you know what type it is.
- This is probably the best option from an OO perspective.
- You may need to temporarily store data in a non-
Vehicle
structure as you gather it, but you don't need to worry about changing the type later.
In your described scenario, I suspect #1 is the best choice. Simply have logic which says "If the object has its type set to Car
, then show this, if it's set to Truck
show this." It's not great OOP design, but it handles the "Vehicle of unknown type" the best.
Best Answer
Well, your design has problems, that's certain, and you've obfuscated the problem a bit too much here.
What I can suggest, based on what you've given, is that, instead of this:
do this:
where Class1 implements WrappedProp like this:
That is to say that the "application" (or whatever object holds a reference to your class1/parent) should not access the child class (or, know about it at all for that matter). From what I can tell, what you're really doing is providing some kind of container or wrapper with your parent class, but not completely wrapping or containing the child type.