Related
I am reading Head First Object Oriented Design to get a better understanding of OOP concepts.
Polymorphism is explained as:
Airplane plane = new Airplane();
Airplane plane = new Jet();
Airplane plane = new Rocket();
You can write code that works on the superclass, like an airplane, but will work with any of the subclasses. :- * Hmmm.. ..I got this one.*.
It further explains:
-> So how does polymorphism makes code flexible?
Well, if you need new functionality, you could write a new subclass of
AirPlane. But since your code uses the superclass, your new class will work
without any changes to the rest of your code.
Now I am not getting it. I need to create a sublass of an airplane. For example: I create a class, Randomflyer. To use it I will have to create its object. So I will use:
Airplane plane = new Randomflyer();
I am not getting it. Even I would have created an object of a subclasses directly. Still I don't see a need to change my code anywhere when I will add a new subclass. How does using a superclass save me from making extra changes to the rest of my code?
Say you have the following (simplified):
Airplane plane = new MyAirplane();
Then you do all sorts of things with it:
List<Airplane> formation = ...
// superclass is important especially if working with collections
formation.add(plane);
// ...
plane.flyStraight();
plane.crashTest();
// ... insert some other thousand lines of code that use plane
Thing is. When you suddenly decide to change your plane to
Airplane plane = new PterdodactylSuperJet();
all your other code I wrote above will just work (differently, of course) because the other code relies on the interface (read:public methods) provided by the general Airplane class, and not from the actual implementation you provide at the beginning. In this way, you can pass on different implementations without altering your other code.
If you hadn't used an Airplane superclass and just written MyAirplane and PterdodactylSuperJet in the sense that you replace
MyAriplane plane = new MyAirplane();
with
PterdodactylSuperJet plane = new PterdodactylSuperJet();
then you have a point: the rest of your code may still work. But that just happens to work, because you wrote the same interface (public methods) in both classes, on purpose. Should you (or some other dev) change the interface in one class, moving back and forth between airplane classes will render your code unusable.
Edit
By on purpose I mean that you specifically implement methods with the same signatures in both MyAirplane and PterodactylSuperJet in order for your code to run correctly with both. If you or someone else change the interface of one class, your flexibility is broken.
Example. Say you don't have the Airplane superclass and another unsuspecting dev modifies the method
public void flyStraight()
in MyAirplane to
public void flyStraight (int speed)
and assume your plane variable is of type MyAirplane. Then the big code would need some modifications; assume that's needed anyway. Thing is, if you move back to a PterodactylSuperJet (e.g. to test it, compare it, a plethora of reasons), your code won't run. Whygodwhy. Because you need to provide PterodactylSuperJet with the method flyStraight(int speed) you didn't write. You can do that, you can repair, that's alright.
That's an easy scenario. But what if
This problem bites you in the ass a year after the innocent modification? You might even forget why you did that in the first place.
Not one, but a ton of modificatios had occurred that you can't keep track of? Even if you can keep track, you need to get the new class up to speed. Almost never easy and definitely never pleasant.
Instead of two plane classes you have a hundred?
Any linear (or not) combination of the above?
If you had written an Airplane superclass and made each subclass override its relevant methods, then by changing flyStraight() to flyStraight(int) in Airplane you would be compelled to adapt all subclasses accordingly, thus keeping consistency. Flexibility will therefore not be altered.
End edit
That's why a superclass stays as some kind of "daddy" in the sense that if someone modifies its interface, all subclasses will follow, hence your code will be more flexible.
A very simple use-case to demonstrate the benefit of polymorphism is batch processing of a list of objects without really bothering about its type (i.e. delegating this responsibility to each concrete type). This helps performing abstract operations consistently on a collection of objects.
Let's say you want to implement a simulated flight program, where you would want to fly each and every type of plane that's present in your list. You simply call
for (AirPlane p : airPlanes) {
p.fly();
}
Each plane knows how to fly itself and you don't need to bother about the type of the planes while making this call. This uniformity in the behaviour of the objects is what polymorphism gives you.
Other people have more fully addressed your questions about polymorphism in general, but I want to respond to one specific piece:
I am not getting it, even I would have create an object of subclasses
directly.
This is actually a big deal, and people go to a lot of effort to avoid doing this. If you crack open something like the Gang of Four, there are a bunch of patterns dedicated to avoiding just this issue.
The main approach is called the Factory pattern. That looks something like this:
AirplaneFactory factory = new AirplaneFactory();
Airplane planeOne = factory.buildAirplane();
Airplane planeTwo = factory.buildJet();
Airplane planeThree = factory.buildRocket();
This gives you more flexibility by abstracting away the instantiation of the object. You might imagine a situation like this: your company starts off primarily building Jets, so your factory has a buildDefault() method that looks like:
public Airplane buildDefault() {
return new Jet();
}
One day, your boss comes up to you and tells you that the business has changed. What people really want these days are Rockets -- Jets are a thing of the past.
Without the AirplaneFactory, you'd have to go through your code and replace possibly dozens of calls to new Jet() with new Rocket(). With the Factory pattern, you can just make a change like:
public Airplane buildDefault() {
return new Rocket();
}
and so the scope of the change is dramatically reduced. And since you've been coding to the interface Airplane rather than the concrete type Jet or Rocket, this is the only change you need to make.
Suppose you have methods in your Controller class of Planes like
parkPlane(Airplane plane)
and
servicePlane(Airplane plane)
implemented in your program. It will not BREAK your code.
I mean, it need not to change as long as it accepts arguments as AirPlane.
Because it will accept any Airplane despite of actual type, flyer, highflyr, fighter, etc.
Also, in a collection:
List<Airplane> plane; // Will take all your planes.
The following example will clear your understanding.
interface Airplane{
parkPlane();
servicePlane();
}
Now your have a fighter plane that implements it, so
public class Fighter implements Airplane {
public void parkPlane(){
// Specific implementations for fighter plane to park
}
public void servicePlane(){
// Specific implementatoins for fighter plane to service.
}
}
The same thing for HighFlyer and other clasess:
public class HighFlyer implements Airplane {
public void parkPlane(){
// Specific implementations for HighFlyer plane to park
}
public void servicePlane(){
// specific implementatoins for HighFlyer plane to service.
}
}
Now think your controller classes using AirPlane several times,
Suppose your Controller class is AirPort like below,
public Class AirPort{
AirPlane plane;
public AirPlane getAirPlane() {
return airPlane;
}
public void setAirPlane(AirPlane airPlane) {
this.airPlane = airPlane;
}
}
here magic comes as Polymorphism makes your code more flexible because,
you may make your new AirPlane type instances as many as you want and you are not changing
code of AirPort class.
you can set AirPlane instance as you like (Thats called dependency Intection too)..
JumboJetPlane // implementing AirPlane interface.
AirBus // implementing AirPlane interface.
Now think of If you create new type of plane, or you remove any type of Plane does it make difference to your AirPort?
No, Because we can say the The AirPort class refers the AirPlane polymorphically.
As far as I understand, the advantage is that, for example, in a airplane combat game, you have to update all airplanes' positions at every loop, but you have several different airplanes. Let's say you have:
MiG-21
Waco 10
Mitsubishi Zero
Eclipse 500
Mirage
You don't want to have to update their movements and positions in separate like this:
Mig21 mig = new Mig21();
mig.move();
Waco waco = new Waco();
waco.move();
Mitsubishi mit = new Mitsubishi();
mit.move();
...
You want to have a superclass that can take any of this subclasses (Airplane) and update all in a loop:
airplaneList.append(new Mig21());
airplaneList.append(new Waco());
airplaneList.append(new Mitsubishi());
...
for(Airplane airplane : airplanesList)
airplane.move()
This makes your code a lot simpler.
You are completely correct that sub-classes are only useful to those who instantiate them. This was summed up well by Rich Hickey:
...any new class is itself an island; unusable by any existing code written by anyone, anywhere. So consider throwing the baby out with the bath water.
It is still possible to use an object which has been instantiated somewhere else. As a trivial example of this, any method which accepts an argument of type "Object" will probably be given an instance of a sub-class.
There is another problem though, which is much more subtle. In general a sub-class (like Jet) will not work in place of a parent class (like Airplane). Assuming that sub-classes are interchangable with parent classes is the cause of a huge number of bugs.
This property of interchangability is known as the Liskov Substitution Principle, and was originally formulated as:
Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.
In the context of your example, T is the Airplane class, S is the Jet class, x are the Airplane instances and y are the Jet instances.
The "properties" q are the the results of the instances' methods, the contents of their properties, the results of passing them to other operators or methods, etc. We can think of "provable" as meaning "observable"; ie. it doesn't matter if two objects are implemented differently, if there is no difference in their results. Likewise it doesn't matter if two objects will behave differently after an infinite loop, since that code can never be reached.
Defining Jet as a sub-class of Airplane is a trivial matter of syntax: Jet's declaration must contain the extends Airplane tokens and there mustn't be a final token in the declaration of Airplane. It is trivial for the compiler to check that objects obey the rules of sub-classing. However, this doesn't tell us whether Jet is a sub-type of Airplane; ie. whether a Jet can be used in place of an Airplane. Java will allow it, but that doesn't mean it will work.
One way we can make Jet a sub-type of Airplane is to have Jet be an empty class; all of its behaviour comes from Airplane. However, even this trivial solution is problematic: an Airplane and a trivial Jet will behave differently when passed to the instanceof operator. Hence we need to inspect all of the code which uses Airplane to make sure that there are no instanceof calls. Of course, this goes completely against the ideas of encapsulation and modularity; there's no way we can inspect code which may not even exist yet!
Normally we want to sub-class in order to do something differently to the superclass. In this case, we have to make sure that none of these differences is observable to any code using Airplane. This is even more difficult than syntactically checking for instanceof; we need to know what all of that code does.
That's impossible due to Rice's Theorem, hence there's no way to check sub-typing automatically, and hence the amount of bugs it causes.
For these reasons, many see sub-class polymorphism as an anti-pattern. There are other forms of polymorphism which don't suffer these problems though, for example "parameteric polymorphism" (referred to as "generics" in Java).
Liskov Substitution Principle
Comparison between sub-classing and sub-typing
Parameteric polymorphism
Arguments against sub-classing
Rice's theorem
One good example of when polymorphism is useful:
Let us say you have abstract class Animal, which defines methods and such common to all animals, such as makeNoise()
You then could extend it with subclasses such as Dog, Cat, Tiger.
Each of these animals overrides the methods of the abstract class, such as makeNoise(), to make these behaviors specific to their class. This is good because obiously each animal makes a different noise.
Here is one example where polymorphism is a great thing: collections.
Lets say I have an ArrayList<Animal> animals, and it is full of several different animals.
Polymorphism makes this code possible:
for(Animal a: animals)
{
a.makeNoise();
}
Because we know that each subclass has a makeNoise() method, we can trust that this will cause each animal object to call their specific version of makeNoise()
(e.g. the dog barks, the cat meows, the cow moos, all without you ever even having to worry about which animal does what.)
Another advantage is apparent when working with a team on a project. Let's say another developer added several new animals without ever telling you, and you have a collection of animals which now has some of these new animal types (which you dont even know exist!). You can still call the makeNoise() method (or any other method in the animal superclass) and trust that each type of animal will know what to do.
The nice thing about this animal superclass is that you can a extend a superclass and make as many new animal types as you want, without changing ANYTHING in the superclass, or breaking any code.
Remember the golden rule of polymorphism. You can use a subclass anywhere a superclass type object is expected.
For example:
Animal animal = new Dog;
It takes a while to learn to think polymorphically, but once you learn your code will improve a lot.
Polymorphism stems from inheritance. The whole idea is that you have a general base class and more specific derived classes. You can then write code that works with the base class... and polymorphims makes your code not only work with the base class, but all derived classes.
If you decide to have your super class have a method, say getPlaneEngineType(), and you make a new child class "Jet which inherits from Plane". Plane jet = new Jet() will/can still access the superclass's getPlaneEngineType. While you could still write your own getJetEngineType() to basically override the superclass's method with a super call, This means you can write code that will work with ANY "plane", not just with Plane or Jet or BigFlyer.
I don't think that's a good example, since it appears to confuse ontology and polymorphism.
You have to ask yourself, what aspect of the behaviour of a 'Jet' is different from an 'Airplane' that would justify complicating the software to model it with a different sub-type? The book's preview cuts off after one page into the example, but there doesn't seem any rationale to the design. Always ask yourself if there is a difference in behaviour rather than just adding classes to categorise things - usually that's better done with a property value or composing strategies than with sub-classes.
An example (simplified from a major project I lead in the early noughties) would be that an Aeroplane is final but has various properties of abstract types, one of which is the engine. There are various ways of calculating the thrust and fuel use of an engine - for fast jets bi-cubic interpolation table of values of thrust and fuel rate against Mach and throttle (and pressure and humidity sometimes), for Rockets the table method but does not require compensation for stalling the air at the engine intake; for props a simpler parametrised 'bootstrap' equation can be used. So you would have three classes of AbstractAeroEngine - JetEngine, RocketEngine and BootstrapEngine which would have implementations of methods which returned thrust and fuel use rate given a throttle setting and the current Mach number. (you should almost never sub-type a non-abstract type)
Note that the differences between the types of AbstractAeroEngine, although related to the different real world engines, are entirely differences in the how the software calculates the engine's thrust and fuel use - you are not constructing an ontology of classes which describe a view of the real world, but specialising the operations performed in the software to suit specific use cases.
How does using a superclass save me from making extra changes to rest of my code?
As all your engine calculations are polymorphic, it means that when you create an aeroplane, you can bolt on whatever engine thrust calculation suits it. If you find you have to cater for another method of calculating the thrust (as we did, several times) then you can add another sub-type of AeroEngine - as long as the implementation it supplies provides the trust and fuel rate, then the rest of the system doesn't care about the internal differences - the AeroPlane class will still ask its engine for the thrust. The aeroplane only cares that it has an engine which it can use the same way as any other engine, only the creation code has to know the type of the engine to bolt onto it, and the implementation of ScramJetEngine only cares about supersonic jet calculations - the parts of AeroPlane which calculate lift and drag, and the strategy for flying it don't have to change.
Polymorphism is powerful given that when there's a need to change a behavior you can change it by overriding a method.
Your superclass inherits its properties and behaviors to your subclasses extended by it. Thus it is safe to implicitly cast an object whose type is also from its superclass. Those common methods to your subclasses make them useful to implement an API. With that, polymorphism gives you the ability to extend a functionality of your code.
Polymorphism gains properties and all behaviors and interfaces of the super class. So is the behavior of a plane really the same as a jet?
I have a class which represents a set of numbers. The constructor takes three arguments: startValue, endValue and stepSize.
The class is responsible for holding a list containing all values between start and end value taking the stepSize into consideration.
Example: startValue: 3, endValue: 1, stepSize = -1, Collection = { 3,2,1 }
I am currently creating the collection and some info strings about the object in the constructor. The public members are read only info strings and the collection.
My constructor does three things at the moment:
Checks the arguments; this could throw an exception from the constructor
Fills values into the collection
Generates the information strings
I can see that my constructor does real work but how can I fix this, or, should I fix this? If I move the "methods" out of the constructor it is like having init function and leaving me with an not fully initialized object. Is the existence of my object doubtful? Or is it not that bad to have some work done in the constructor because it is still possible to test the constructor because no object references are created.
For me it looks wrong but it seems that I just can't find a solution. I also have taken a builder into account but I am not sure if that's right because you can't choose between different types of creations. However single unit tests would have less responsibility.
I am writing my code in C# but I would prefer a general solution, that's why the text contains no code.
EDIT: Thanks for editing my poor text (: I changed the title back because it represents my opinion and the edited title did not. I am not asking if real work is a flaw or not. For me, it is. Take a look at this reference.
http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/
The blog states the problems quite well. Still I can't find a solution.
Concepts that urge you to keep your constructors light weight:
Inversion of control (Dependency Injection)
Single responsibility principle (as applied to the constructor rather than a class)
Lazy initialization
Testing
K.I.S.S.
D.R.Y.
Links to arguments of why:
How much work should be done in a constructor?
What (not) to do in a constructor
Should a C++ constructor do real work?
http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/
If you check the arguments in the constructor that validation code can't be shared if those arguments come in from any other source (setter, constructor, parameter object)
If you fill values into the collection or generate the information strings in the constructor that code can't be shared with other constructors you may need to add later.
In addition to not being able to be shared there is also being delayed until really needed (lazy init). There is also overriding thru inheritance that offers more options with many methods that just do one thing rather then one do everything constructor.
Your constructor only needs to put your class into a usable state. It does NOT have to be fully initialized. But it is perfectly free to use other methods to do the real work. That just doesn't take advantage of the "lazy init" idea. Sometimes you need it, sometimes you don't.
Just keep in mind anything that the constructor does or calls is being shoved down the users / testers throat.
EDIT:
You still haven't accepted an answer and I've had some sleep so I'll take a stab at a design. A good design is flexible so I'm going to assume it's OK that I'm not sure what the information strings are, or whether our object is required to represent a set of numbers by being a collection (and so provides iterators, size(), add(), remove(), etc) or is merely backed by a collection and provides some narrow specialized access to those numbers (such as being immutable).
This little guy is the Parameter Object pattern
/** Throws exception if sign of endValue - startValue != stepSize */
ListDefinition(T startValue, T endValue, T stepSize);
T can be int or long or short or char. Have fun but be consistent.
/** An interface, independent from any one collection implementation */
ListFactory(ListDefinition ld){
/** Make as many as you like */
List<T> build();
}
If we don't need to narrow access to the collection, we're done. If we do, wrap it in a facade before exposing it.
/** Provides read access only. Immutable if List l kept private. */
ImmutableFacade(List l);
Oh wait, requirements change, forgot about 'information strings'. :)
/** Build list of info strings */
InformationStrings(String infoFilePath) {
List<String> read();
}
Have no idea if this is what you had in mind but if you want the power to count line numbers by twos you now have it. :)
/** Assuming information strings have a 1 to 1 relationship with our numbers */
MapFactory(List l, List infoStrings){
/** Make as many as you like */
Map<T, String> build();
}
So, yes I'd use the builder pattern to wire all that together. Or you could try to use one object to do all that. Up to you. But I think you'll find few of these constructors doing much of anything.
EDIT2
I know this answer's already been accepted but I've realized there's room for improvement and I can't resist. The ListDefinition above works by exposing it's contents with getters, ick. There is a "Tell, don't ask" design principle that is being violated here for no good reason.
ListDefinition(T startValue, T endValue, T stepSize) {
List<T> buildList(List<T> l);
}
This let's us build any kind of list implementation and have it initialized according to the definition. Now we don't need ListFactory. buildList is something I call a shunt. It returns the same reference it accepted after having done something with it. It simply allows you to skip giving the new ArrayList a name. Making a list now looks like this:
ListDefinition<int> ld = new ListDefinition<int>(3, 1, -1);
List<int> l = new ImmutableFacade<int>( ld.buildList( new ArrayList<int>() ) );
Which works fine. Bit hard to read. So why not add a static factory method:
List<int> l = ImmutableRangeOfNumbers.over(3, 1, -1);
This doesn't accept dependency injections but it's built on classes that do. It's effectively a dependency injection container. This makes it a nice shorthand for popular combinations and configurations of the underlying classes. You don't have to make one for every combination. The point of doing this with many classes is now you can put together whatever combination you need.
Well, that's my 2 cents. I'm gonna find something else to obsess on. Feedback welcome.
As far as cohesion is concerned, there's no "real work", only work that's in line (or not) with the class/method's responsibility.
A constructor's responsibility is to create an instance of a class. And a valid instance for that matter. I'm a big fan of keeping the validation part as intrinsic as possible, so that you can see the invariants every time you look at the class. In other words, that the class "contains its own definition".
However, there are cases when an object is a complex assemblage of multiple other objects, with conditional logic, non-trivial validation or other creation sub-tasks involved. This is when I'd delegate the object creation to another class (Factory or Builder pattern) and restrain the accessibility scope of the constructor, but I think twice before doing it.
In your case, I see no conditionals (except argument checking), no composition or inspection of complex objects. The work done by your constructor is cohesive with the class because it essentially only populates its internals. While you may (and should) of course extract atomic, well identified construction steps into private methods inside the same class, I don't see the need for a separate builder class.
The constructor is a special member function, in a way that it constructor, but after all - it is a member function. As such, it is allowed to do things.
Consider for example c++ std::fstream. It opens a file in the constructor. Can throw an exception, but doesn't have to.
As long as you can test the class, it is all good.
It's true, a constructur should do minimum of work oriented to a single aim - successful creaation of the valid object. Whatever it takes is ok. But not more.
In your example, creating this collection in the constructor is perfectly valid, as object of your class represent a set of numbers (your words). If an object is set of numbers, you should clearly create it in the constructor! On the contrary - the constructur does not perform what it is made for - a fresh, valid object construction.
These info strings call my attention. What is their purpose? What exactly do you do? This sounds like something periferic, something that can be left for later and exposed through a method, like
String getInfo()
or similar.
If you want to use Microsoft's .NET Framework was an example here, it is perfectly valid both semantically and in terms of common practice, for a constructor to do some real work.
An example of where Microsoft does this is in their implementation of System.IO.FileStream. This class performs string processing on path names, opens new file handles, opens threads, binds all sorts of things, and invokes many system functions. The constructor is actually, in effect, about 1,200 lines of code.
I believe your example, where you are creating a list, is absolutely fine and valid. I would just make sure that you fail as often as possible. Say if you the minimum size higher than the maximum size, you could get stuck in an infinite loop with a poorly written loop condition, thus exhausting all available memory.
The takeaway is "it depends" and you should use your best judgement. If all you wanted was a second opinion, then I say you're fine.
It's not a good practice to do "real work" in the constructor: you can initialize class members, but you shouldn't call other methods or do more "heavy lifting" in the constructor.
If you need to do some initialization which requires a big amount of code running, a good practice will be to do it in an init() method which will be called after the object was constructed.
The reasoning for not doing heavy lifting inside the constructor is: in case something bad happens, and fails silently, you'll end up having a messed up object and it'll be a nightmare to debug and realize where the issues are coming from.
In the case you describe above I would only do the assignments in the constructor and then, in two separate methods, I would implement the validations and generate the string-information.
Implementing it this way also conforms with SRP: "Single Responsibility Principle" which suggests that any method/function should do one thing, and one thing only.
I have a data class which encapsulates relevant data items in it. Those data items are set and get by users one by one when needed.
My confusion about the design has to do with which object should be responsible for handling the update of multiple properties of that data object. Sometimes an update operation will be performed which affects many properties at once.
So, which class should have the update() method?. Is it the data class itself or another manager class ? The update() method requires data exchange with many different objects, so I don't want to make it a member of the data class because I believe it should know nothing about the other objects required for update. I want the data class to be only a data-structure. Am I thinking wrong? What would be the right approach?
My code:
class RefData
{
Matrix mX;
Vector mV;
int mA;
bool mB;
getX();
setB();
update(); // which affects almost any member attributes in the class, but requires many relations with many different classes, which makes this class dependant on them.
}
or,
class RefDataUpdater
{
update(RefData*); // something like this ?
}
There is this really great section in the book Clean Code, by Robert C. Martin, that speaks directly to this issue.
And the answer is it depends. It depends on what you are trying to accomplish in your design--and
if you might have more than one data-object that exhibit similar behaviors.
First, your data class could be considered a Data Transfer Object (DTO). As such, its ideal form is simply a class without any public methods--only public properties -- basically a data structure. It will not encapsulate any behavior, it simply groups together related data. Since other objects manipulate these data objects, if you were to add a property to the data object, you'd need to change all the other objects that have functions that now need to access that new property. However, on the flip side, if you added a new function to a manager class, you need to make zero changes to the data object class.
So, I think often you want to think about how many data objects might have an update function that relates directly to the properties of that class. If you have 5 classes that contain 3-4 properties but all have an update function, then I'd lean toward having the update function be part of the "data-class" (which is more of an OO-design). But, if you have one data-class in which it is likely to have properties added to it in the future, then I'd lean toward the DTO design (object as a data structure)--which is more procedural (requiring other functions to manipulate it) but still can be part of an otherwise Object Oriented architecture.
All this being said, as Robert Martin points out in the book:
There are ways around this that are well known to experienced
object-oriented designers: VISITOR, or dual-dispatch, for example.
But these techniques carry costs of their own and generally return the
structure to that of a procedural program.
Now, in the code you show, you have properties with types of Vector, and Matrix, which are probably more complex types than a simple DTO would contain, so you may want to think about what those represent and whether they could be moved to separate classes--with different functions to manipulate--as you typically would not expose a Matrix or a Vector directly as a property, but encapsulate them.
As already written, it depends, but I'd probably go with an external support class that handles the update.
For once, I'd like to know why you'd use such a method? I believe it's safe to assume that the class doesn't only call setter methods for a list of parameters it receives, but I'll consider this case as well
1) the trivial updater method
In this case I mean something like this:
public update(a, b, c)
{
setA(a);
setB(b);
setC(c);
}
In this case I'd probably not use such a method at all, I'd either define a macro for it or I'd call the setter themselves. But if it must be a method, then I'd place it inside the data class.
2) the complex updater method
The method in this case doesn't only contain calls to setters, but it also contains logic. If the logic is some sort of simple property update logic I'd try to put that logic inside the setters (that's what they are for in the first place), but if the logic involves multiple properties I'd put this logic inside an external supporting class (or a business logic class if any appropriate already there) since it's not a great idea having logic reside inside data classes.
Developing clear code that can be easily understood is very important and it's my belief that by putting logic of any kind (except for say setter logic) inside data classes won't help you achieving that.
Edit
I just though I'd add something else. Where to put such methods also depend upon your class and what purpose it fulfills. If we're talking for instance about Business/Domain Object classes, and we're not using an Anemic Domain Model these classes are allowed (and should contain) behavior/logic.
On the other hand, if this data class is say an Entity (persistence objects) which is not used in the Domain Model as well (complex Domain Model) I would strongly advice against placing logic inside them. The same goes for data classes which "feel" like pure data objects (more like structs), don't pollute them, keep the logic outside.
I guess like everywhere in software, there's no silver bullet and the right answer is: it depends (upon the classes, what this update method is doing, what's the architecture behind the application and other application specific considerations).
I've had trouble finding a clear, concise laymans definition of a class. Usually, they give general ideas without specifically spelling it out, and I'm wondering if I'm understanding this correctly. As I understand it, a class is the set of code that controls an object. For example, in an app that has a button for 'Yes' and a button for 'No', and a text box for output, the code that tells the computer what to do when the user uses the Yes button is one class, the code for hitting No is another class, and an object is the two buttons and what they do together to influence the output box. Am I right, or am I confusing terms here?
Thanks
A class is a kind of thing, an object is an actual thing. So, in the real world, "person" is a class, you and I are objects (or instances) of that class. "Car" is a class, my 1996 beater Volvo station wagon is an object.
Objects all have certain similarities in form and function because of the class they belong to. When I say my station wagon is a "car", you have a pretty good idea of what it looks like, what it's used for, and what it can do. But objects of a class can also differ from each other. Just because something's a car doesn't tell you exactly what shape it is or how many seats it has or what color it is.
In the example you gave, it's likely that the yes and no buttons are both objects of the class "button" (or some similar name) and that the differences in their behavior are due to changes added by the programmer without his or her bothering to create a new class. However, it is possible that the programmer made the decision to make each type of button a subclass of the original class "button".
What's a subclass? Well, if you think of "car" as a class, it is obvious that there are several intermediate "kinds" of things between "car" and "Larry's 1996 beater Volvo station wagon". These could be "station wagon" and "Volvo station wagon". So my car would be an instance of "Volvo station wagon" which itself would be subclass of "station wagon" which would be a subclass of "car". From the "car" part, we know a good deal about my object, from the "station wagon" part we learn a little more, and from the "Volvo station wagon" a little more still.
The way in which classes and subclasses are arranged is a decision made by the programmer. In my example above, another programmer might have made the classes "car", "Volvos", "pre-Ford", and "Wagons". It depends on the problem you're trying to solve.
This is going to be a very simplified explanation. A class is a set of functions and variables and is used to create objects. I think it's good to use real examples instead of dog / bark / talk etc.
Class Email
Subject (string)
Message (string)
ToAddress (string)
FromAddress (string)
Send (function)
When you call 'new Email()' it creates a new object with those variables and functions. Then you can populate the variables and send it.
In object-oriented programming, a class is a type for objects. An object is a bundle of data together with functionality that can operate in the context of that data; the definition of what the object is and does when it is first created is determined by its class.
Like a type for data, the class of an object specifies what is common to all instances of that class. Instances, which are the objects themselves, then get to override that common baseline (otherwise there's not much point having distinct instances). In many OO systems, instances may or may not have new members that are not part of the class definition.
What that means in the context of a specific object-oriented language is going to differ from language to language. But if you think of classes as types, and build on that, you won't go far wrong.
A class is basically a way to organize your code.
It allows you to put all of the code related to one abstraction (think "concept" or "idea") in one place.
As an example - in your example of an app, the Window with the two buttons, a text box, and some code for handling what happens when the user types in the information may be organized into a single class: something like "PromptWindow". This class would be made up of multiple classes internally (two buttons, a textbox, etc) This would probably be used by some separate class, which would create an instance of the PromptWindow class, call a method on the class to show the window, then use the results.
At the very basis, there's procedural code:
var a = 4
var b = 5;
print a + b;
… and so on, statements following statements…
To make such pieces of code reusable, you make a function out of them:
function a_plus_b() {
var a = 4
var b = 5;
print a + b;
}
Now you can use that piece of code as often as you want, but you only had to write it once.
Usually an application depends on a certain way of how pieces of code and variables have to work together. This data needs to be processed by that function, but cannot be processed by that other function.
function foo(data) {
…do something…
return data;
}
function bar(data) {
…do something else…
return data;
}
a = "some data";
b = 123456;
a = foo(a);
b = bar(b);
c = bar(a); // ERROR, WRONG DATA FOR FUNCTION
To help group these related parts together, there are classes.
class A {
var data = 'some data';
function foo() {
…do something…
return data;
}
}
The function foo now has a variable data that is "bundled" with it in the same class. It can operate on that variable without having to worry about that it may be the wrong kind of data. Also there's no way that data can accidentally end up in function bar, which is part of another class.
The only problem is, there's only one variable data here. The function is reusable, but it can only operate on one set of data. To solve this, you create objects (also called instances) from the class:
instance1 = new A();
instance2 = new A();
instance1 and instance2 both behave exactly like class A, they both know how to perform function foo (now called an instance method) and they both hold a variable data (now called an instance variable or attribute), but that variable data can hold different data for both instances.
That's the basics of classes and objects. How your particular "OK", "Cancel" dialog box is implemented is a different story. Both buttons could be linked to different methods of different classes, or just to different methods of the same class, or even to the same method of the same class. Classes are just a way to logically group code and data, how that's going to be used is up to you.
In a language agnostic fasion, I would describe a class as being an object that contains related information.
A person class would have methods like Talk(), Walk(), Eat(); and attributes like Height, Color, Language, etc.
A class is like a blueprint of things that you can instantiate, and also procedures that are related to each other.
If you have a Database class, you might have many methods related to databases that do all sorts of voodoo with a database.
A class is a bunch of code that defines an entity in your application. There may be many such entities, but the behaviour of each is the same, as defined by the class. The class will typically define fields, whose contents are local to the instances (or objects) of that class. It is these fields that provide the objects with state and make them distinguishable from one another.
To use your example, there might be a Button class that defines what a button is in your application. This class would then be instantiated twice to provide two objects: one for the "No" button and another for the "Yes" button. The Button class could have a Text field/property that defines what text it contains – this could be set to "No" and "Yes" on the appropriate Button instances to give them their different appearances.
As for the click behaviour of the buttons, this would typically be implemented via the observer pattern, in which the subject class (Button in this case) maintains a list of separate "observer" objects which it notifies whenever some event occurs (i.e. when the button is clicked).
You should look at some sample code, in your language of choice. Just reading about the concept of classes will not answer many questions.
For example, I could tell you that a class is a "blueprint" for an object. Using this class, you can instantiate multiple such objects, each one of them (potentially) having unique attributes.
But you didn't understand a thing, now, did you? Your example with the buttons is very limited. Classes have nothing to do with user interfaces or actions or whatever. They define a way of programming, just like functions/methods/whatever you want to call them do.
So, to give a concrete example, here's a class that defines a ball, written in Python:
class Ball:
color = ''
def __init__(self, color):
self.color = color
def bounce(self):
print "%s ball bounces" % self.color
blueBall = Ball("blue")
redBall = Ball("red")
blueBall.bounce()
redBall.bounce()
Running this produces the expected output:
blue ball bounces
red ball bounces
However, there is much more to classes than I described here. Once you understand what a class is, you go on to learn about constructors, destructors, inheritance and a lot of other good stuff. Break a leg :)
From the definition of Class at Wikipedia:
In object-oriented programming, a
class is a construct that is used as
a blueprint (or template) to create
objects of that class. This blueprint
describes the state and behavior that
the objects of the class all share. An
object of a given class is called an
instance of the class. The class that
contains (and was used to create) that
instance can be considered as the type
of that object, e.g. an object
instance of the "Fruit" class would be
of the type "Fruit".
A class usually represents a noun,
such as a person, place or (possibly
quite abstract) thing - it is a model
of a concept within a computer
program. Fundamentally, it
encapsulates the state and behavior of
the concept it represents. It
encapsulates state through data
placeholders called attributes (or
member variables or instance
variables); it encapsulates behavior
through reusable sections of code
called methods.
Your understanding of a Class isn't at all incorrect but to make things clear consider the following...
The Yes and No buttons plus the TextBox are usually specified within a class taking for example code written in C# (Microsoft .NET Framework). Let's name this class MyClass.
The actions the buttons cause are handled by what are called handlers (methods). You could write your code in such a way that when you click the Yes button something gets written in the TextBox.
To instantiate MyClass you'd do the following:
MyClass myClass = new MyClass();
myClass.ButtonYes += new EventHandler(YourMethodForYes);
myClass.ButtonNo += new EventHandler(YourMethodForNo);
myClass.TextBox.Text = "Yes button was clicked";
Hope you get the idea.
I wrote usually above because this cenario you described could be implemented in a number of ways. OOP gives you plenty of ways to accomplish the same task.
Besides the definition of Class I think that reading about Object Oriented Programming (OOP) can help you a lot to understand it even more. Take a look at Fundamental Concepts.
Let's say you have a Person object and it has a method on it, promote(), that transforms it into a Captain object. What do you call this type of method/interaction?
It also feels like an inversion of:
myCaptain = new Captain(myPerson);
Edit: Thanks to all the replies. The reason I'm coming across this pattern (in Perl, but relevant anywhere) is purely for convenience. Without knowing any implementation deals, you could say the Captain class "has a" Person (I realize this may not be the best example, but be assured it isn't a subclass).
Implementation I assumed:
// this definition only matches example A
Person.promote() {
return new Captain(this)
}
personable = new Person;
// A. this is what i'm actually coding
myCaptain = personable.promote();
// B. this is what my original post was implying
personable.promote(); // is magically now a captain?
So, literally, it's just a convenience method for the construction of a Captain. I was merely wondering if this pattern has been seen in the wild and if it had a name. And I guess yeah, it doesn't really change the class so much as it returns a different one. But it theoretically could, since I don't really care about the original.
Ken++, I like how you point out a use case. Sometimes it really would be awesome to change something in place, in say, a memory sensitive environment.
A method of an object shouldn't change its class. You should either have a member which returns a new instance:
myCaptain = myPerson->ToCaptain();
Or use a constructor, as in your example:
myCaptain = new Captain(myPerson);
I would call it a conversion, or even a cast, depending on how you use the object. If you have a value object:
Person person;
You can use the constructor method to implicitly cast:
Captain captain = person;
(This is assuming C++.)
A simpler solution might be making rank a property of person. I don't know your data structure or requirements, but if you need to something that is trying to break the basics of a language its likely that there is a better way to do it.
You might want to consider the "State Pattern", also sometimes called the "Objects for States" pattern. It is defined in the book Design Patterns, but you could easily find a lot about it on Google.
A characteristic of the pattern is that "the object will appear to change its class."
Here are some links:
Objects for States
Pattern: State
Everybody seems to be assuming a C++/Java-like object system, possibly because of the syntax used in the question, but it is quite possible to change the class of an instance at runtime in other languages.
Lisp's CLOS allows changing the class of an instance at any time, and it's a well-defined and efficient transformation. (The terminology and structure is slightly different: methods don't "belong" to classes in CLOS.)
I've never heard a name for this specific type of transformation, though. The function which does this is simply called change-class.
Richard Gabriel seems to call it the "change-class protocol", after Kiczales' AMOP, which formalized as "protocols" many of the internals of CLOS for metaprogramming.
People wonder why you'd want to do this; I see two big advantages over simply creating a new instance:
faster: changing class can be as simple as updating a pointer, and updating any slots that differ; if the classes are very similar, this can be done with no new memory allocations
simpler: if a dozen places already have a reference to the old object, creating a new instance won't change what they point to; if you need to update each one yourself, that could add a lot of complexity for what should be a simple operation (2 words, in Lisp)
That's not to say it's always the right answer, but it's nice to have the ability to do this when you want it. "Change an instance's class" and "make a new instance that's similar to that one" are very different operations, and I like being able to say exactly what I mean.
The first interesting part would be to know: why do you want/need an object changes its class at runtime?
There are various options:
You want it to respond differently to some methods for a given state of the application.
You might want it to have new functionality that the original class don't have.
Others...
Statically typed languages such as Java and C# don't allow this to happen, because the type of the object should be know at compile time.
Other programming languages such as Python and Ruby may allow this ( I don't know for sure, but I know they can add methods at runtime )
For the first option, the answer given by Charlie Flowers is correct, using the state patterns would allow a class behave differently but the object will have the same interface.
For the second option, you would need to change the object type anyway and assign it to a new reference with the extra functionality. So you will need to create another distinct object and you'll end up with two different objects.