I’m mostly thinking of PHP here, but if you want to refer to other languages that’s fine.
An object has a method that requires data contained in another class of object.
Should I extract that data from the other object into a variable and then send just that data to the requesting object?
Or should I pass the entire data-containing object into the data-requiring object, and then have the requesting object perform the data extraction operations?
I’m asking because I’m working on a big project that I’ve written 100% of the code for, and some of my early code takes string or numeric arguments, but my later code seems to be leaning toward passing around objects. As I bump into some old code, I’m wondering if I should convert it to object parameters.
I think as with every CS question, it depends.
- If you are planning to use a lot of the functionality provided by the passed class it is great:
- this is basically how you can have common functions like sort, which can take any type of object and as long as it has the required methods implemented it will work.
- passing objects facilitates programming to an interface
- If you are just extracting one (lets say integer) thing and using the receiving classes methods to operate on it, it is bad:
- you may unintentionally copy the object while passing
- if you don’t use the whole object the code can be misleading
So I advise you to look at your functions on a case by case basis and not make generalizations for your whole code base.
It depends, and I try to discuss this by using a more real-world example.
For example, lets say you have a Person
object with attributes like FirstName
, Surname
, NameAffix
, DateOfBirth
, Gender
. And you are going to create some methods to process that data (for example, for a formatted report).
First, lets think of a method GetFullPersonNameFormatted
, which should return a combination of FirstName
, Surname
and NameAffix
in a specificially formatted string (assume that it does not make sense to put that method directly into the Person
class for some reasons). Shall you pass the attributes one-by-one or the whole Person
object? Well, I probably would pass the Person
object at a whole, since this method creates an abstractions on persons, and if the Person changes internally, I only want to change GetFullPersonNameFormatted
internally, not the calling code.
Now lets think of a method GetDateOfBirthFormatted
, it should return the date-of-birth in a specificially formatted way. Shall you pass the attribute, or the whole Person object? I probably would start with a more general method FormatDate(date)
, not specificially for Persons, which would be much more reusable that a method GetDateOfBirthFormatted(person)
, but it may also make sense to have additionally a
string GetDateOfBirthFormatted(Person person)
{
return FormatDate(person.DateOfBirth);
}
method for the same reason as in the first example: to create an abstraction on persons. If you really need that method, depends (for example, if there would be just one call to GetDateOfBirthFormatted
in your whole program, you may better avoid creating that method and directly use FormatDate(person.DateOfBirth)
instead.
So the answer for “should your method take the whole object or not?” depends mostly on “how much does your method need from that object?”, but also on “what kind of abstraction you are going to create?”. A big indicator for better using objects is when you have lots of methods getting the same group of attributes over and over again, for example, when you pass FirstName
, Surname
, NameAffix
into several methods. This may also be an indicator that these attributes belong to a newly-to-create class (think of a program where you don’t have a Person class so far: methods like that may be an indicator that you should create one).
There can be another reason not to pass objects, but only attributes: decoupling. Lets say the GetFullPersonNameFormatted
is in module A, and the class definition of Person
is in module B, and the call to GetFullPersonNameFormatted
is in module C which references A and B. If you do not want to reference B from A, to keep those two modules completely independent from each other, then you need to define GetFullPersonNameFormatted
without any Person
parameter.
To summarize: it is not always a simple black-and-white decision, and there are different shades of grey.
I think the best rule of thumb is to only send as a parameter what is actually needed. The reason is re-use. If you only need an integer as a parameter, passing in an object means that the same method cant (without some type wrangling) work in some other context when you want to use that same method but dont have an instance of the required type of object to use as a parameter.
Compare:
public function ReceiveData($s) {
$data = ExtractData($s)
ProcessData($data)
}
...
$destination.ReceiveData($source)
With:
$destination.ProcessData(ExtractData($source))
The latter has several concrete advantages:
- Testability. It’s easier to unit test ExtractData and ProcessData separately rather than one method (ReceiveData) that does both.
- Reusability. If you have a different kind of $source that $destination might want to receive, then you can still use ProcessData by simply using a different ExtractData function (or even the same ExtractData function if the two kinds of $source have a common interface).
- Readability. Using ExtractData as an argument to ProcessData makes the data extraction explicit, rather than an implicit part of ReceiveData.
This relates to the single responsiblity principle (a method should only have one responsiblity).
-
I think that you can set an object as a property of class,and you can pass an object as an argument of method.
Choice which one is determined in the scene. -
If your instance use the data or function of an object,you should set the object as a property of your instance.For example,”Proxy Pattern”,you always call an object’s method to accomplish tasks.
-
But if your instance use the data of function of any object,you should pass one object as an argument of a method.For example,”Visitor Pattern”, your class visit a different object everytime.So you should pass an object as argument.
1