4
\$\begingroup\$

Code in Java but should be readable also for c#...

Let's assume I have a class with some reference types. Example:

class MyClass {
   private int uniqueId;
   private double doubleValue;
   private MyReferenceType refType1;
   // ...

   public MyClass(int id, double doubleValue, MyReferenceType refType){
      this.id = id;
      this.doubleValue = doubleValue;
      this.refType1 = refType;  // seems dangerous - I want to create new object with the same state instead of adding a reference to an existing one...
   }
   // ...
}

The question is what approach of constructing such an object do you prefer:

Option 1 In constructor:

public MyClass(int id, double doubleValue, MyReferenceType refType){
      // ...
      this.refType1 = new MyReferenceType(refType); // MyReferenceType has some "copy" constructor
}

In code:

MyClass mc = new MyClass(1, 1.0, someRefTypeInstance);

or

Option 2: In constructor:

public MyClass(int id, double doubleValue, MyReferenceType refType){
      // ...
      this.refType1 = refType;
   }

In code:

MyClass mc = new MyClass(1, 1.0, new MyReferenceType(someRefTypeInstance));

Which approach do you find more reasonable and you use in practice?

\$\endgroup\$
2
  • \$\begingroup\$ It depends on what you want to do with your class. If you need more flexibility (and of course, risks) the option 2 is ok but in my humble and personal opition, I prefer the option 1. I think it's more safe and reusable. \$\endgroup\$ Commented Oct 17, 2013 at 10:54
  • \$\begingroup\$ If you have control over MyReferenceType, a third option is to make it immutable. \$\endgroup\$
    – Dan Lyons
    Commented Oct 17, 2013 at 18:01

4 Answers 4

1
\$\begingroup\$

Basically I use option 1. The usage of constructor is initialize the properties and creating an object in memory. Value types sets the default values ​​(int = 0 etc), reference types sets null. If you want use own default values, you must use own constructor. This is option 1 in your post. In my opinion this is the safest and most logical option.

\$\endgroup\$
1
\$\begingroup\$

In Option #2 you cannot be sure that user of your class will pass new Object as a parameter. If you really want to create a clone of parameter you should create on yourself or implement some clone method on MyReferenceType

\$\endgroup\$
1
  • \$\begingroup\$ "In Option #2 you cannot be sure that user of your class will pass new Object as a parameter." +1 yeah, I agree to the above \$\endgroup\$
    – Alexandr
    Commented Oct 17, 2013 at 12:04
1
\$\begingroup\$

I do C# but I believe the same applies to Java: I use constructor signatures to statically declare what a type's dependencies are; constructors basically initialize private readonly fields, so I go with #2. It's not the job of a type to create another type imho (i.e. avoid new as it induces tight coupling), unless it's an infrastructure type or a factory class.

Tight coupling aside, I think the problem stems from the "copy constructor" of MyReferenceType. Why doesn't MyClass just take the instance it's given? In your comment I want to create new object with the same state instead of adding a reference to an existing one, the only reason for the why here, is "because I want that". Not good enough, that doesn't explain the need for breaking SRP and strong-coupling MyClass with MyReferenceType.

\$\endgroup\$
1
\$\begingroup\$

Making a copy of an object has a benefit: safety from unexpected changes. It also has costs: it takes up more memory, uses more CPU cache, and adds pressure to the garbage collector. Making copies that won't be modified is a waste - you're paying the cost with no benefit. So you should only make a copy if you know that you'll need it.

The only code that knows for sure that the parameter will be modified is the code that's going to modify it. So whoever is going to modify that parameter should make the copy. Otherwise you risk screwing up shared state, or making a bunch of unnecessary copies.

So: Option #1 if the child object is going to modify the parameter, Option #2 if the caller is going to modify the parameter. If neither is going to modify it, then don't make useless copies.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.