• Post Reply Bookmark Topic Watch Topic
  • New Topic

Object creation scenario and requirement  RSS feed

 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All,

I have an existing java class which is having some functions implemented based on interface. Now I want to add new class which will have same functions and will get instantiated within constructor of my original class. So consider below example,



So if client class calls add() method, it should be Add() from class B. Limitation i have with my code is i can make changes in class A only. This is needed for backward compatibility where i want Class A to be untouched. This is because this class A gets instantiated through various scripts and method like Add() are used.

Thank you in advance. I hope my question is clear.
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, your question is not clear.

You say you have a class with functions based on an interface. I don't see an interface. The new class will be instantiated from a constructor of the original class. I don't see that happening either. If you mean replacing the current instance with another, that's not possible. You say you can only make changes to class A, but you also say that class A needs to be untouched.

Please explain clearly what the goal and the problem is. Why do you need to replace the behavior of A?
 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
okay my mistake. I haven't wrote that in code but class-A implements an interface. This class-A was providing some functionality to clients using methods like add(). Now I have 2 clients, one wants to use implementation in class-A and other wants implementation of class-B method like add(). Untouched i meant i want to deprecate class-A's add() method in future. thats why i dont want changes in that for mixed behavior which will result in complications while deprecating it. New clients for class-A will should use class-B's add() method based on some flag or value like i passed in constructor using below code. 



Is it possible? like can i cast an object to subclass object so that it will start referring methods of class B.
 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One more thing is client only know about class-A. They have written own implementations using class-A. So i want to redirect them to new implementation based on some condition or flag that will be passed by them to class-A constructor.
 
Dave Tolls
Ranch Foreman
Posts: 3001
37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can't do this inside the A constructor.
This looks like something (if I've understood you correctly anyway) closer to a factory method.
You provide the details to the factory method, and that returns the correct subclass.



Obviously, if your current code isn't set up for this then there will be refactoring required, however you're going to need to refactor anyway.
 
Junilu Lacar
Sheriff
Posts: 11433
175
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Despite OP's unclear description, this smells very strongly of poor design choices and a gross misuse of the type hierarchy mechanisms in Java. Client code should be programmed to the interface, which should provide a general contract for behavior. Subtypes that implement the interface must adhere to that contract even when they implement their behavior in unique and specific ways.
 
Junilu Lacar
Sheriff
Posts: 11433
175
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I understand what OP's goal is now: To minimize ripple effect. You want to deprecate class A but you have a lot of client code that instantiates and uses class A that you don't want to go through and change to use class B instead. So, your solution is to try to make the class A constructor somehow return an instance of class B instead.

No, you can't do that in Java.

The problem is really that your design is inflexible and too coupled to a specific implementation class. It's too coupled because you have the code for creating a dependency mixed in with the code that uses a dependency. You need to refactor your client code (scripts) where this is happening so that you're passing in the implementation that was created elsewhere into the scripts that are programmed to the interface and use it. That is, if you create it, don't use it. Conversely, if you use it, have somebody else create it for you.

 
Junilu Lacar
Sheriff
Posts: 11433
175
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's an illustration of the problem I think OP has:

Along comes a change in requirements where instead of A, you have to use B now. Now you have to go through all your 1527 scripts and find where you're instantiating A with new A() and change it to new B() instead. What a pain, right? So, you're thinking "Wouldn't it be sweet if new A() actually created a B object instead?" -- Yeah, I can see how you might think that would be sweet but that's NOT how Java works.

You need to refactor and separate creation from utilization:

If you are able to refactor this to Dependency Injection pattern, that might be even better:


You're going to have to make more changes than you probably want to right now but this is the price you have to pay to make future changes easier to make.

In the future, if the same kind of situation arises with your B implementation class that needs to be changed to a C implementation class, you only need to go to the createA script to upgrade your program and all the scripts will follow without any change or ripple effect whatsoever.
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:That is, if you create it, don't use it. Conversely, if you use it, have somebody else create it for you.

This bears emphasis.

This problem explains exactly why, when a methods needs to do something, you pass the things it needs to do it with through the method parameters, or you assign them to fields from constructor parameters. This is what Junilu means by Dependency Injection. If the objects you require need to be created on the fly, and you don't know (or don't want to know) the precise type, you pass an abstract factory instead. A good example of this are database connections. When you have a repository of entities that need to be retrieved from a database, the repository needs to open connections on the fly, but you don't want to know the exact type of the connection, because you might want to swap to a different database later. Here's how that looks:

The getThing() method needed connections created on the fly for it to do its job, but instead of creating them itself, it asked the abstract connection factory to create the connection for it. That means it doesn't need to know about the exact subclass of Connection. It also needed an AbstractConnectionFactory for it to do its job, but instead of creating a factory itself, it asked for one in the constructor. Again, it doesn't need to know about the exact subclass of the AbstractConnectionFactory. When your application switches to a new database implementation, all that needs to change is that the application's entry point substitutes a new AbstractConnectionFactory implementation for the old one, and the rest of the application will remain working the same way it always did.

* Note that in this example, I used the names AbstractConnectionFactory and connectionFactory.createConnection(), because those names clearly reflect the concepts we talked about earlier. In an actual Java application, you would use DataSource and dataSource.getConnection().
 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you Junilu and Stephan.

You got it correct Junilu. But I cant change this class to interface. Now what i am planning to do is create 2 service classes.




What do you think about this approach?
 
Stephan van Hulst
Saloon Keeper
Posts: 7928
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That does nothing to improve the situation. You're still creating your own services. Why not pass the service directly to A's constructor?

Anyway, to deprecate A, just mark it with @Deprecated, let all new code you write use the interface that A and B implement, and after a while you can remove support for A completely.
 
Junilu Lacar
Sheriff
Posts: 11433
175
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
vijay jamadade wrote:But I cant change this class to interface. Now what i am planning to do is create 2 service classes.
...
What do you think about this approach?

I agree with Stephan, you still don't address the root cause. What exactly is preventing you from turning A into an interface? Give us a concrete code example so we can understand what you are facing. Otherwise, it just looks like you're choosing to implement a kludge so you can avoid doing something that will improve quality but also bears the cost of carrying unmanaged technical debt.
 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Based on name of this class, people have wrote customized solutions in our application. we have around 200 clients which uses our product and customize things using different scripts where they create instance of this class and access functions which are exposed to them. This class itself implements an interface in upper layer in our product. These customized scripts get interpreted using bean shell library. so scripts can be in any language which are understood by bean shell implementation. Thats why i said i cant change this class and i have to live with it. 
 
Junilu Lacar
Sheriff
Posts: 11433
175
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
vijay jamadade wrote:Thats why i said i cant change this class and i have to live with it. 

Famous last words.

The thing with pain is that one way or another, sooner or later, you're going to have to deal with it. Skirting around a problem may make the pain temporarily go away but when it comes back later, and you can bet it will come back, its bite will be even more painful and more difficult to ignore or work around.

If your API provided an interface in the first place and clients, no matter how many there may be, were programmed to an implementation of that interface, then you shouldn't be obligated to take on the burden of maintaining support for those clients. Those clients should themselves be refactored so that they are resilient to change.

In practical terms, you may have to give clients reasonable time and means for transitioning to a better API design. I strongly encourage you to consider Stephan's suggestion and provide a factory instead. To me this is the best way forward for you. Your way may be expedient in the short term but in the long term, you'll be caught in a trap of your own making and I'm afraid you'll find it difficult to extricate yourself from it when you realize how big of a mistake you made. What's more, clients will hate you (or your company) for it because you led them down a path that would make migration/refactoring even more difficult and costly.
 
vijay jamadade
Ranch Hand
Posts: 252
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I agree Junilu. I think i will raise this issue for analysis and changes in design and it will take lot of time for resolution. Many people use this thing.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!