繁体   English   中英

Java - Getter/Setter、行为和接口

[英]Java - Getter/Setter, behavior and Interfaces

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

假设,我有以下课程:

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

第二个报告需要一个额外的参数释放才能正常工作,但我的接口定义为没有execute方法的参数,所以我用一个 setter 方法解决它,所以它看起来像:

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

所以我不喜欢这个额外的rep.setRelease 我看起来很奇怪和做作 - 这个类的用户可能会感到困惑,例如,如果我在 Spring 中将该类作为单例 bean,它是潜在错误的来源,如果它被第二次请求而有人忘记了第二次触发rep.setRelease 除了将它放入构造函数(我想将它变成一个 spring bean)之外,处理这种情况的最佳做法是什么?

假设您可以更改界面,这里有一些我能想到的解决方案:

解决方案#1

void execute(Optional<String> release);

或者

void execute(@Nullable String release);

然后将它们用于Report类作为execute(Optional.empty())execute(null)

解决方案#2

void execute(String... release);

然后将其用于Report类作为execute()并将其用于ReportWithSetter类作为execute("R1.1")

解决方案#3

定义两个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");
  }

您还可以将这两个方法设为接口中的default方法,这样您的实现类就不必担心实现不受支持的方法。


使用对您来说最易读和最易于维护的那个。

方案一:Spring依赖注入——字段注入:

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也会很奇怪。 所以“Release”类必须包含你的“String release”。

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

解决方案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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM