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).
精彩评论