1

i want to load wrapper class with one shot, but I couldn't able. may be still my oops skills are weak. i feel we can write much better way

 public class WrapperA{
    public Id sobjerecid;
    public sobjrec__c sobjrec;
    public classA classobjA;
     public classB classobjB;
    public WrapperA(Id recid){
        this.sobjerecid= recId;
        this.sobjrec = [Select Id,xy__c,ab__c,sss_c,bb__c,ccc__c from sobjec__c where Id =:recid Limit 1];
        this.prepareclassA();
        this.prepareclassobjB(); 
        
    }
    private void prepareclassA (){
    classA classaobj = new classA();
        
    classaobj.bf = 'spi';
    classaobj.Sc= 'xyz';
    classaobj.RS= 'abc';
    classaobj.SS= '123q';
    this.classobjA = classaobj;

}
    
    private void prepareclassobjB(){
    classB  classBobj = new classB();
    innerclassofclassB[] innerclassBlistobj  = new List<innerclassofclassB>();
    innerclassofclassB innerclassBobj= new innerclassofclassB();

    classBobj.prop1= sobjrec.xy__c;
    classBobj.prop2=sobjrec.ab__c;
    classBobj.prop3 =sobjrec.sss_c;
           
    innerclassBobj.innerclassBprop1= sobjrec.bb__c;
    innerclassBobj.innerclassBprop2= sobjrec.ccc__c;
    
   
    innerclassBlistobj.add(innerclassBobj);
    classBobj.InnerclassB= innerclassBlistobj;

    this.classobjB= classBobj;
}
    
}

public mainClass {
  WrapperA wrapA = new WrapA(recId);// i want to load etire wrapper object with this line
  }

2 Answers 2

6

Constructors are typically called by using the new keyword. There's also super() and this(), but those probably aren't what you're looking for (super() is used to call the parent class's constructor, this() is used when a single class has multiple constructors to help re-use code).

Your prepareClassA() and prepareClassObjB() methods look like they should be constructors in ClassA and ClassB respectively (with the constructor for ClassB taking an argument so you can set prop1, prop2, and prop3).

In the end, your wrapper constructor should just simply do the following

public class WrapperA{
    // member vars remain unchanged

    public WrapperA(Id recId){
        // unaffected code unchanged
        classObjA = new classA();
        classObjB = new classB(sobjRec);
    }

    // no extra methods to set up ClassObjA or B
    // that's the responsibility of the constructors for those classes

}

That'd work, but that general approach (creating object instances used by a class inside of the same class) makes for code that is more fragile and harder to test. If classA changes so that it no longer has a no-arg constructor, you'd need to also change your wrapper class.

It may not matter so much in this case, but the generally accepted practice is to inject dependencies into a class (as opposed to creating things in the class). Unsurprisingly, this concept is called dependency injection. If you get the feeling that you're just shifting code around (it's taking code that was part of the wrapper, and forcing it to be done in the thing that creates/uses the wrapper), that's because that is exactly what you're doing.

The benefit of doing that, however, is that it helps to isolate changes. Changing how ClassB works no longer means that WapperA needs to change as well.

Applied to your wrapper class...

public class WrapperA{
    // It doesn't appear that sobjRec__c is used for anything besides getting
    //   data into the ClassB instance.
    // Since we're using dependency injection, other code will worry about getting
    //   the right data for ClassB, so we don't need to worry about it here
    public ClassA myAInstance;
    public ClassB myBInstance;
    
    public WrapperA(ClassA aInstance, ClassB bInstance){
        myAInstance = aInstance;
        myBInstance = bInstance;
    }
}
2
  • Thanks well formatted answer, but where should i set sobjrec__c , do i need to prepare sobjrec__c record before calling my wrapper constructor? that means i need to call classB constructor with sobjrec__c record then call wrapper constructor with classB instance is it right?
    – sdandamud1
    Commented Dec 6, 2020 at 14:36
  • 1
    @sdandamud1 In my first example, there is no change to how you get your sobjrec__c instance. In my second example (dependency injection), sobjrec__c is no longer needed in the wrapper class and your order of operations sounds correct (get an sobjectrec__c instance, pass it to the ClassB constructor, call the ClassA constructor, pass both ClassA and ClassB instances to your wrapper's constructor).
    – Derek F
    Commented Dec 6, 2020 at 14:55
5

In addition to Derek's answer, consider the builder pattern

public class WrapperA {

  ClassA classA
  ClassB classB

  public WrapperA withclassA(ClassA val)  {this.classA = val; return this;}
  public WrapperB withclassA(ClassB val)  {this.classB = val; return this;}
}

public class ClassA {
  String sc;
  String rs;
  String ss;
  public ClassA withSc(String val) {this.sc = val; return this;}
  public ClassA withRs(String val) {this.rs = val; return this;}
  public ClassA withSs(String val) {this.ss = val; return this;}
}

public class ClassB {
  .. similar to ClassA
}

and then you can instantiate in one statement

WrapperA wrapA = new WrapperA()
     .withClassA(new ClassA()
         .withRs('abc')
         .withSc('def'
         .withSS('ghi')
     )
     .withClassB(new ClassB()
          .withXX(..)
          ...
     );

This approach avoids too many arg methods that can be flagged by static code analyzers; is infinitely extensible, is very readable, avoids having to know the order of arguments, makes setting up testmethods easier, and provides other benefits of a facade between the object and how it is invoked (i.e. supporting default values)

1
  • this is the way i expect , thanks for wonderful answer
    – sdandamud1
    Commented Dec 9, 2020 at 14:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .