Java-Getter / Setter,行为和接口

问题描述

我有一个问题,理论上有点:

假设,我有以下课程:

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;
  }
}

第二个报告需要一个额外的参数 release 才能正常工作,但是我的界面没有为execute方法定义参数,因此我使用setter方法解决它,所以它将看起来像:

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

所以我不喜欢这个额外的rep.setRelease。我看起来很奇怪,很人为-此类的用户可能会感到困惑,例如,如果我在Spring中将该类设为单例bean,那么如果第二次请求该类并且有人忘记了,则它是潜在错误的来源再次触发rep.setRelease。除了将其放入构造函数(我想使其成为Spring bean)之外,处理这种情况的最佳实践是什么?

解决方法

假设您可以更改界面,以下是我可以想到的一些解决方案:

解决方案#1

ID

void execute(Optional<String> release);

,然后将它们作为void execute(@Nullable String release); Report用于execute(Optional.empty())类。

解决方案2

execute(null)

,然后将其用于void execute(String... release); 类的Reportexecute()类的ReportWithSetter类。

解决方案3

在界面中同时定义execute("R1.1")void execute();。然后在实施时,将void execute(String release);放入不需要的方法中。例如,在UnsupportedOperationException类中,您可以这样做:

Report

您还可以在界面中将这两种方法都设置为 public void execute(){ //do some logic } public void execute(String release){ throw new UnsupportedOperationException("Use the overloaded method"); } ,因此您的实现类不必担心实现不受支持的方法。


使用对您而言最易读和可维护的方式。

,

解决方案1:弹簧依赖注入-字段注入:

Spring的依赖注入与反射一起使用,因此不需要Setter方法。
因此,如果将Report类设置为Spring Bean并使用@Autowired注入另一个Bean,则不需要Setter方法。
看起来像这样:

@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
  }
}

我将“ String release”更改为“ Release release”,因为制作“ String” bean也很奇怪。因此,“发行”类将必须包含您的“字符串发行版”。

如果“字符串发布”仅包含一些配置的值,则该值在运行时不会更改。然后,您可以使用@Value从属性文件中读取其String值。

解决方案2:Spring构造函数注入:

构造函数注入是另一种选择,甚至更推荐使用。 然后,您的Report Bean将如下所示:

@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
  }
}
,

如果要创建同一接口的不同类的实例,则工厂方法模式是很好的选择。

class MyFactory {
       ReportInterface createInstance(Class clazz,String... args) {
           if (Report.class.equals(clazz)) {
               return new Report();
           }
           if (ReportWithSetter.class.equals(clazz)) {
               return new ReportWithSetter(args[0]);
           }
           throw new IllegalArgumentException(clazz.getName());
       }
}

,

Spring当然提供了自动装配,但是引入@AutoWire应该是出于系统目的。

您可以在这里执行两阶段执行,即工厂。

class ReportFactory /*ReportWithSetter*/ {

  private final Repository rep;
  private final String release;

  private final ReportInterface report = ...;

  ReportFactory (Repository rep,String release) {
     this.rep = rep;
     this.release = release;
  }

  public ReportInterface report() {
      return report;
  }
}

new ReportFactory(rep,release).execute();

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...