4

After reading this thread, I understand that it is not possible to assign to this in Java. But are there any workarounds? I have the following situation. I'm writing a subclass B, but the base class A does not have any explicit constructors or methods that would allow to create the object given my arguments. The only available way is to call some external function F():

public class B extends A {   
   public B(some args) {     
       A a = F(some args);
       this = a;
   }
}

Both A and F() are from external libraries, A is a pretty complex object, and F() implements a sophisticated algorithm.

The only solution I can think of, is simply not to make a subclass:

public class B {
   public A a;   
   public B(some args) {     
       a = F(some args);      
   }
}

It doesn't look very appealing though. What would be the least ugly solution in this situation?

Community
  • 1
  • 1
ojy
  • 2,402
  • 2
  • 18
  • 23
  • 7
    `but the base class A does not have any explicit constructors or methods that would allow to create the object given my arguments` Seems like that's by design. Don't try to break encapsulation and use composition over inheritance. – Sotirios Delimanolis Aug 29 '14 at 18:44
  • Is it not possible to parameterize B's constructor with whatever data is required by its super constructor? – Mark W Aug 29 '14 at 18:45
  • @SotiriosDelimanolis: that should be part of an answer. – Hovercraft Full Of Eels Aug 29 '14 at 18:45
  • If B really does extend A, why is any conversion necessary? In other words, what would F() do, that you couldn't simply implement directly into b with, say, an `actLikeA` flag – Gus Aug 29 '14 at 18:45
  • @Gus, B does extend A. At least it's supposed to. This problem is coming from chemoinformatics field. Class A refers to some molecular structure, with all the chemical elements, bonds, 3D structure, etc. And F() returns a molecule from it's string representation. I have no idea how this algorithm works, it's beyond the scope of my expertize. I just want to extend this thing with a few more custom attributes and methods. – ojy Aug 29 '14 at 18:55
  • OK I see. One option, then, is to just keep an internal copy of `A` and pass method calls directly to it; except for when you want to change the behavior. The disadvantage is that there's probably a lot of boilerplate to this approach, if `A` has a lot of public methods. – Gus Aug 29 '14 at 19:00
  • Somewhere in the method `F()` it must be calling one of the constructors of `A`, if it returns an `A`. Or at least getting an `A` from somewhere. If you have the source code for `F`, can you check whether the constructor it uses is `public` or `protected`? If so, you should be able to call it using the `super` keyword from the constructor of `B`. – Dawood ibn Kareem Aug 29 '14 at 19:47
  • @David, unfortunately, other than calling a constructor on A, F() also performs a lot of gets and sets and other things, and overall implements a pretty complicated algorithm to properly initialize A, which I do not entirely understand. – ojy Aug 29 '14 at 20:02
  • If they are gets and sets on the created `A` object, then you probably need them in your `B` constructor. If they are gets and sets on some other object, you probably don't need them. – Dawood ibn Kareem Aug 29 '14 at 21:02

1 Answers1

4

Your solution to not make a subclass is correct one. That is composition, and you should always prefer it over inheritance. So even if A had the right constructor, you shouldn't make B a subclass of A unless you have a specific requirement forcing you to do it.

Only use inheritance when you need to pass instance of B as instance of A. But really, you should rarely need to do that, unless you are dealing with poorly designed code. You should use interfaces, so you would would have class A which implements some interface, let's call it interface IA. Then instead of being subclass of A, you simpley have class B implements IA. And then you have the private member variables of type A inside B, if you need it.

(There's also the matter of when to use interfaces and when to use abstract base classes, but I'll leave it out of this answer.)


Note that modern Java IDEs make creating delegates very easy, and frankly, coding Java without such IDE is wrong way to code Java. Writing all that boilerplate by hand is error-prone, tedious, and makes you hate Java for no reason. With modern IDE, first add that private member variable a, possibly place cursor on it or right click it for context menu, and find "Insert code..." or some such option. From there find something like "Add delegates...". Then you should simply be able to click which methods of A you want to add to B and have them delegated. The IDE should create code in B like this.

int method() {
    return a.method();
}

This makes actually following "composition over inheritance" quite nice and easy.

hyde
  • 60,639
  • 21
  • 115
  • 176
  • Thanks! Not exactly what I was hoping for, but sounds like the only way to do it at this point. – ojy Sep 03 '14 at 20:13