Trying to avoid code duplication when implementing abstract methods - java

I have the following abstract class defined here:
#Slf4j
public abstract class PublishMappingService {
#Autowired
private ErpPackageRepository erpPackageRepository;
#Autowired
private PubSubClient pubSubClient;
#Autowired
private RequestInfo requestInfo;
public abstract void publishMappingUpdateEvent(MappingsEntity mappingsEntity);
public abstract void publishMappingUpdateEvent(List<MappingsEntity> mappingsEntityList);
public void publishEvent(String companyId) {
ErpPackage erpPackage;
try {
erpPackage = erpPackageRepository.getSelectedErpPackageForCompanyId(companyId);
pubSubClient.publishEventAsync(
new MappingUpdatedEvent(
erpPackage.getPartnerId(), erpPackage.getCompanyId(),
erpPackage.getErpId(), this.requestInfo.getCorrelationId(),
null
)
);
} catch (NotFoundException e) {
log.error("MappingsRepository::publishEvent: This entity is not registered with ECP - companyId: {}", companyId, e);
} catch (Exception e) {
log.error("MappingsRepository::publishEvent: Failed to publish MappingUpdatedEvent for {}", companyId, e);
}
}
}
Let's say I have two classes (A and B) that inherit from the abstract base class
public class A extends PublishMappingService {
// public class B extends PublishMappingService {
#Override
public void publishMappingUpdateEvent(MappingsEntity mappingsEntity) {
// Identical in Class B
if (mappingsEntity != null) {
String companyId = mappingsEntity.getCompanyId();
publishEvent(companyId);
}
}
#Override
public void publishMappingUpdateEvent(List<MappingsEntity> mappingsEntityList) {
// Identical in Class B
if (mappingsEntityList != null && !mappingsEntityList.isEmpty()) {
String companyId = mappingsEntityList.get(0).getCompanyId();
publishEvent(companyId);
}
}
}
Essentially, the problem is that when I override and implement the abstract methods defined in my subclasses, these methods will be identical across every subclass.
Since I'm not avoiding code duplication with my abstract class, I thought of just making a utility class instead. However, from what I've read, utility classes should only be created if every method can be declared as static which I can't do so as seen in the behavior of the publishEvent method.
I also thought about using an interface with default methods but that approach also wouldn't work since then my instance variables would be need to be static and final, which isn't possible with autowired fields.
Thus, I'm asking to see if there's any alternative ways I can approach refactoring my code to avoid duplication here? Thanks!

If all implementations of an abstract method are identical, then there's no need to have the abstract method in the first place. Move the implementation to the base class.
An abstract method forces all derived classes to implement this method (or be abstract themselves). If child classes are free to implement or override the method, it doesn't have to be abstract.

Related

When I extend an interface A with interface B, will A's methods be available for free to B's implementors?

I'm curious how this all works. I have an interface, let's call it A. When I look at A, it has most of the methods I need, but not all, and I don't have control over interface A, so I extend it with interface B which implements the 1 or whatever number of methods that I need on top of A.
public interface B extends A {
String doSomethingFun(String blah);
}
A has an implementation class called Client. In just a second I'm going to create my own implementation class of B called MyDefaultClient.
I then create a concrete class that implements B, like this:
#Component
public class MyDefaultClient implements B {
private A myClient;
#Autowired
public MyDefaultClient(A myClient) {
this.myClient = myClient;
}
#Override
public String doSomethingFun(String filename) {
// custom business logic
}
#Override
public String serviceName() {
return myClient.serviceName();
}
#Override
public void close() {
myClient.close();
}
}
serviceName() and close() are methods that A forces its implementors to implement. There are other methods though that have default implementations that aren't forcing me to implement them, I assume simply because they have default implementations.
At this point I have a concrete class that I can instantiate in other places and call all of both A and B's methods on it. But is that only because in the interface there are default implementations for these methods, like this?
default Blah someMethodInA(String thing) {
throw new UnsupportedOperationException();
}
If I use this code and call myDefaultClient.doSomethingFun("hello") I'm pretty certain that will do the thing I want it to do. But what about if I call myDefaultClient.someMethodInA()? Will it call the implemented method in Client, which is A's implementor? Or will it fall on the floor and complain with an UnsupportedOperationException? If the latter, is there any way I can structure this so that I can call all of A's methods from B's implementor?
If you want MyDefaultClient to inherit implementations from Client, then it has to extend Client, like this:
class MyDefaultClient extends Client implements B
{
...
}
Then, if Client implements A, you will only have to provide implementations for the new methods that B adds.
or... you can continue your current pattern and explicitly delegate all the calls you want to a field of type A, but you will have to do them all explicitly, even the methods with default implementations. The default implementations will continue the throw exceptions if you don't override them.
An interface can have any number of default methods. Check this for more details. Given below is an example to demonstrate how default methods and extending an interface work:
public interface InterfaceA {
public void toBeImplementedA();
default void hello() {
System.out.println("Hello");
}
default void hi() {
System.out.println("Hi");
}
}
public interface InterfaceB extends InterfaceA {
public void toBeImplementedB();
}
public class AnImplClass implements InterfaceB {
#Override
public void toBeImplementedA() {
System.out.println("toBeImplementedA");
}
#Override
public void toBeImplementedB() {
System.out.println("toBeImplementedB");
}
}
public class Main {
public static void main(String[] args) {
InterfaceB obj = new AnImplClass();
obj.toBeImplementedA();
obj.toBeImplementedB();
obj.hello();
obj.hi();
}
}
Output:
toBeImplementedA
toBeImplementedB
Hello
Hi
Feel free to comment in case of any doubt.
Interfaces can contain default methods. These were added to Java so that an interface could be updated without forcing implementing code to be rewritten.¹
Default methods provide an implementation if your implementing class does not implement them.
When you call methods on an object, the overridden method is always called.
Any other implementations in the super classes / interfaces are used when there is a lack of implementation.
Even if you refer to MyDefaultClient as A,
A myImplementation = new MyDefaultClient();
Under the hood myImplementation is still an instance of MyDefaultClient even though the code views it as A. Therefore your overriden method will be used when doSomethingFun is called.
#Override
public String doSomethingFun(String filename) {
// custom business logic
}
¹ Source: https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

How do i ensure implementation of a public static function with interface

Since Java 8, we are able to define static and default methods in interface. But I need to ensure a public static method say foo() to be implemented in all the classes that implements a particular interface say interface A. How do I do that , or is it at all possible ?
The interface A:
package com.practice.misc.interfacetest;
public interface A {
public static Object foo(); //Eclipse shows error : 'This method requires a body instead of a semicolon'
String normalFunc();
}
Class B :
package com.practice.misc.interfacetest;
public class B implements A{
#Override
public String normalFunc() {
return "B.normalFunc";
}
//I need to ensure that I have to define function foo() too
}
Class C :
package com.practice.misc.interfacetest;
public class C implements A{
#Override
public String normalFunc() {
return "C.normalFunc";
}
//I need to ensure that I have to define function foo() too
}
Edit 1:
Actual case :
I have one public static method getInstance() (returning Singleton instance of that class) in all the implementing classes, and I want to ensure all the future classes other developers write must have that static method implemented in their classes. I can simply use reflection to return that instance by calling the getInstance() method from a static method of the interface, but I wanted to make sure that everyone implements the getInstance() in all the implementing classes.
static methods from interface are not inherited (1). They are inherited in case of a class, but you can not override them (2); thus what you are trying to do is literally impossible.
If you want all classes to implement your method, why not simply make it abstract (and implicitly public) to begin with, so that everyone is forced to implement it.
Eugene already pointed out that static methods can not be overridden. I suggest that you extract the singleton behavior to a separate interface. For example:
public interface A {
String normalFunc();
}
public class B implements A {
#Override
public String normalFunc() {
return "B.normalFunc";
}
// TODO add getInstance for singleton
}
public interface Singleton {
// TODO extensive javadoc to describe expected singleton behavior
A getInstance();
}
public class BSingleton implements Singleton {
#Override
public A getInstance() {
return B.getInstance();
}
}
Finally you can use any object of type BSingleton to get the singleton object of B.

What is the best practice in Java to set a constant required in subclasses?

I have the following situation:
A parent class has a function that depends on a constant. But the only valid place to define that constant is in subclasses (parent class cannot define the constant's value, but it can be used with the constant undefined in 99% of use cases - the constant is a default to use if a specific configuration element is missing).
However, I would like to enforce that any child class inheriting from that parent class must define the value for the constant, since any child classes have to be able to use the other 1% of functionality.
What is the best practice to implement this enforcement in Java, ideally at compile time? (clearly, at runtime, I can simply check if the constant is null/empty in the method using it).
My own solution was to implement a value-getter for the constant as an abstract method in the parent class, and call that in combination with the real setter in the constructor; something like this:
public class HelperClass1 {
private String myConstant;
public void setMyConstant() {} // implemented obviousy
public void myMethod() { // Called from ParentClass's methods
// Do something useful with myConstant
}
}
import HelperClass1;
public abstract class ParentClass {
ParentClass() {
HelperClass1.setMyConstant( getMyConstantValue() );
}
public abstract void getMyConstantValue();
}
public class ChildClass1 extends ParentClass {
public void getMyConstantValue() { return "BUZZ"; }
}
public class ChildClass2 extends ParentClass {
} // Fails to compile without getMyConstantValue()
However, (a) This implementation has a problem (I can't use ParentClass itself, since it's now abstract) without subclassing; and (b) since I'm not a Java developer, I'm afraid that this isn't the best or the most elegant solution. So I'd like to know if there's a best practices approach that improves on what I implemented.
Provide two constructors for the parent class:
One is a protected constructor which takes the constant as an argument.
The other is private constructor which can construct instances of the parent class without setting the constant.
Provide a factory method for the parent class which can call the private no-constant constructor.
Classes that want to get an instance of the parent class can call the factory method. But child classes that want to inherit from the parent class have to call the protected constructer, which can validate that a valid constant was passed.
public class ParentClass {
private final SomeClass myConstant;
protected ParentClass(SomeClass aConstant) {
if (null == aConstant) {
throw new IllegalArgumentException("...");
}
myConstant = aConstant;
}
private ParentClass() {
myConstant = null;
}
public static ParentClass getInstance() {
return new ParentClass();
}
}
public class ChildClass {
public ChildClass() {
super(new SomeClass(42));
}
}
This isn't perfect. Someone could write a child class that passes a bad constant to the superclass constructor, and it wouldn't actually fail until some code tried to construct an instance of the child class.

Can you get the subclass of a Method that was inherited?

Take a look at this code:
public class Main {
public class A {
public final void method() {}
}
public class B extends A {}
public static main() {
try {
Method method = B.class.getMethod("method");
//Returns the name of Main$A, but I want Main$B
System.out.println(method.getDeclaringClass().getName());
} catch (NoSuchMethodException e) {}
}
}
I'm trying to get the class out of an inherited method that I previously have taken from a subclass. The reasoning for this is in my application, I store all methods with a specified annotation by object into a Set<Method> and store the object itself in a Map<Class<?>, Object> which is to easily invoke the method later.
I understand that it would make sense for method.getDeclaringClass() to return Main$A, since that's where it was declared, not Main$B, but I was just wondering if there was an alternative to solve my problem.
You're trying to reindex the class methods in a way that is incompatible with the java standards. I don't think there is a workaround for this; your code should reflect the way things are structured; i.e.
populate your map with the class returned by getDeclaringClass().

Superclass Common Method Implementation

I'm fairly new to OO programming specifically with Java. I have a question pertaining to inheritance.
I have a printing method that I'd like to be common among subclasses. The code in the print method is usable for all subclasses except for a response object that is specific to each individual subclass.
I'm thinking that i need to probably just override the method in each subclass providing the specific implementation. However it feels like there would be a slicker way to keep the common method in the super class and while somehow supplying the specific response object based on the subclass accessing it.
Any thoughts? Sorry if this seems elementary....
You will want an abstract base class that defines what is done, while the child classes define how it is done. Here's a hint as to how such a thing might look
public abstract class BaseClass{
public final String print(){
return "response object: " + responseObject();
}
protected abstract Object responseObject();
}
This is loosely related to the Template Method pattern, which might be of interest to you.
You are absolutely right, there is a better way. If your implementations share a great deal of code, you can use template method pattern to reuse as much implementation as possible.
Define a printReponse method in the superclass, and make it abstract. Then write your print method in the superclass that does the common thing and calls printResponse when needed. Finally, override only printResponse in the subclasses.
public abstract class BasePrintable {
protected abstract void printResponse();
public void print() {
// Print the common part
printResponse();
// Print more common parts
}
}
public class FirstPrintable extends BasePrintable {
protected void printResponse() {
// first implementation
}
}
public class SecondPrintable extends BasePrintable {
protected void printResponse() {
// second implementation
}
}
You can do something like this
public class A {
protected String getResponse(){ return "Response from A"; }
public void print(){
System.out.println( this.getName() );
}
}
public class B extends A {
protected String getResponse(){ return "Response from B"; }
}
A a = new A();
B b = new B();
a.print(); // Response from A
b.print(); // Response from B
i.e. you dont need to override the print method, just the getResponse

Categories

Resources