Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Getter/Setter, behavior and Interfaces

I have a question, a little bit theoretical:

Assume, I have the following classes :

interface ReportInterface {
     void execute();
}

class Report implements ReportInterface {

  private final Repository rep; 

  Report(Repository ref){
     this.rep = ref;
  }

  public void execute(){
     //do some logic
  }
}


class ReportWithSetter implements ReportInterface {

  private final Repository rep;
  private String release;

  ReportWithSetter(Repository ref){
     rep = ref;
  }

  public void execute(){
     if (release == null) throw IlligalArgumentException("release is not specified");
     //do some logic
  }
  
  public void setRelease(String release){
     this.release=release;
  }
}

The second report needs an additional parameter release to work properly, but my interface is defined without parameters for execute method, so I work around it with a setter method, so it would look like:

ReportWithSetter rep2 = new ReportWithSetter (rep);
rep.setRelease("R1.1");
rep.execute();

So I don't like this additional rep.setRelease. I looks weird and artificial - a user of this class may be confused, and for example, if I make the class as a singleton bean in Spring, it is a source of potential error, if it is requested for the second time and somebody forgets to trigger rep.setRelease for the second time. Besides putting it into constructor (I want to make it a spring bean), what would be the best practice to handling this situation?

like image 735
Dr1231 Avatar asked Oct 12 '20 05:10

Dr1231


People also ask

Can we use getter and setter in interface in Java?

You cannot define instance fields in interfaces (unless they are constant - static final - values, thanks to Jon), since they're part of the implementation only. Thus, only the getter and setter are in the interface, whereas the field comes up in the implementation.

Should getters and setters be in interface?

Getters and setters, by their nature, hold information about present fields and concrete implementation, and are not a good fit for an interface.

What is the difference between setter and getter in Java?

Getters and setters are used to protect your data, particularly when creating classes. For each instance variable, a getter method returns its value while a setter method sets or updates its value. Given this, getters and setters are also known as accessors and mutators, respectively.

How does getter and setter works in Java?

Getters and Setters play an important role in retrieving and updating the value of a variable outside the encapsulating class. A setter updates the value of a variable, while a getter reads the value of a variable.


2 Answers

Assuming you are allowed to change the interface, here are a few solutions I can think of:

Solution #1

void execute(Optional<String> release);

or

void execute(@Nullable String release);

and then use them for Report class as execute(Optional.empty()) or execute(null).

Solution #2

void execute(String... release);

and then use it for Report class as execute() and for ReportWithSetter class as execute("R1.1").

Solution #3

Define both void execute(); and void execute(String release); in the interface. Then while implementing, throw UnsupportedOperationException in the method you don't need. For example, in Report class, you would do:

  public void execute(){
     //do some logic
  }

  public void execute(String release){
     throw new UnsupportedOperationException("Use the overloaded method");
  }

You can also make both these methods as default in the interface, so your implementation classes don't have to worry about implementing the unsupported method.


Use whichever is most readable and maintainable for you.

like image 97
Kartik Avatar answered Sep 18 '22 22:09

Kartik


Solution 1: Spring Dependency Injection - Field Injection:

Spring's Dependency Injection works with reflection, so Setter methods are not required.
So if you make your Report class a Spring Bean and use @Autowired to inject another bean, then the Setter method is not required.
It would look like this:

@Component
class ReportWithRelease implements ReportInterface {

@Autowired private final Repository rep;
@Autowired private Release release;

public void execute(){
  if (release == null) throw IlligalArgumentException("release is not specified");
    //do some logic
  }
}

I changed "String release" to "Release release", because making a bean of "String" would be also strange. So the "Release" class would have to contain your "String release".

If "String release" contains only some configured value, which does not change at runtime. Then you can use @Value to read its String value from a properties file.

Solution 2: Spring Constructor Injection:

Constructor injection is another option, which is even more recommended. Then your Report bean would look like this:

@Component
class ReportWithRelease implements ReportInterface {

private Repository rep;
private Release release;

@Autowired
public ReportWithRelease(Repository rep, Release release) {
  this.rep = rep;
  this.release = release;
}

public void execute(){
  if (release == null) throw IlligalArgumentException("release is not specified");
    //do some logic
  }
}
like image 44
Elmar Brauch Avatar answered Sep 21 '22 22:09

Elmar Brauch