Should A method takes some properties from an object or just take the object?
For example
int GetNum(int x, int y)
{
return x+y;
}
then call
开发者_如何学运维 z= GetNum(myobject.x, myobject.y);
or
int GetNum(ClassA myobject)
{
return myobject.x+myobject.y;
}
then call
z = GetNum(myobject);
Pass in the property values to reduce coupling between your classes. The class that defines GetNum
does not need to know about ClassA
in this case.
It is better to reduce coupling\dependencies between classes as this makes your design more flexible. Where you do supply complex types to methods, then supply interfaces instead so that you can vary which particular implementation you pass around. This again makes your design more flexible, and more easily testable.
I think this depends very much on your own coding style.
In my opinion, a method should take an object as an argument if the purpose of that method is linked to that object. For instance, a method to format the fields of an object into a pretty text string should take an object as its arguments.
In your example, the method isn't really related to the object - it could take any two numbers, they don't have to be wrapped up in a particular object to work, so I think the method should take properties as arguments.
I don't think it makes a big difference which style you choose, though.
The general rule I follow is this. Does the method require the object?, or does it require property values of the object? The latter makes the method more usable (as it doesn't require users to create an instance of whatever type has these properties).
What you could do, is provide an overload (thus supporting both):
int GetNum(int x, int y) { return (x + y); }
int GetNum(ClassA obj) { return GetNum(obj.X, obj.Y); }
Ask yourself what are the likely use cases for the method, and then ask if you actually require the need to pass in an instance which wraps the values.
Consider that I might have the following method:
public void ProcessMessage(Result result)
{
// Do something with Result.ReturnedMessage
result.ReturnedMessage.Process(result.Target);
}
It accepts a single instance of a theoretical Result
type, but the reality is, it's only using two arguments, so we could redefine it as:
public void ProcessMessage(Message message, Target target)
{
message.Process(target);
}
This now makes the method usable in potentially more scenarios, and of course, you could define an overload that just routes from ProcessMessage(Result)
to ProcessMessage(Message, Target)
, etc.
On the other hand, if the method forms part of an interface definition:
void ProcessMessage(Result result);
You can't guarantee that a type implementing that method won't require access to more than just the ReturnedMessage
and Target
properties.
Bottom line is, consider you use-cases, and how that fits in with the larger design. Also consider future-proofing... how easy is it to spin up our theoretical Result
type?
As a footnote, this is a very similar argument as to where to pass a value using a specialised type, or a base type, e.g.:
public void DoSomething(List<string> items);
public void DoSomething(IList<string> items);
public void DoSomething(IEnumerable<string> items);
In the above examples, is your method doing anything that explicitly requires the List<string>
type, or will it work with the IList<string>
interface definition... or if you are not adding anything at all.. how about accepting an IEnumerable<string>
instance instead. The less you specialise your method calls, the more widely they can be used.
In this case as chibacity says GetNum doesn't need to know about ClassA. however, you might consider actually adding GetNum as a method of ClassA which calls GetNum passing in the appropriate values. Its not necessarily write but if you are going to do it a lot it might make sense.
I think, that like everything else interesting, the answer is "It depends".
The example may have been simplified too much, to give enough context to answer the question properly. There seems to be three ways of addressing the solution:
1) int GetNum(ClassA myObject){}
2) int ClassA.GetNum(){}
3) int GetNum(int a, int b) {}
In the past, I would have come down in favour of option 2, making GetNum a member of ClassA. It's none of the caller's business how GetNum works, or where it gets the information from, you (the caller) just want to get a number from a ClassA object. The code of option needs to know about the contents of ClassA, so this is inappropriate, even if it just uses two getters. If we knew more about the context, then maybe option one would be better. I can't tell from the question.
There's a huge interest in improving the testability of code at work, especially legacy code. and unless there's a useful unit testing framework already in place, options 1 and 2 require an object of ClassA, be instantiated for testing. In order to make the code testable (especially if ClassA is expensive or impractical to instantiate) we've been going with something like option 3 (or making it a static member of ClassA). This way, you do not need to instantiate or pass around objects that are difficult to make, AND you can easily add complete code test coverage.
As always though, YMMV.
精彩评论