抽象类中的抽象属性

时间:2021-06-01 05:00:49

标签: java spring

我有一个抽象类,其中包含一些使用@Value 设置的配置属性值。我想重用抽象类,但使用另一组配置属性。问题是,这些属性值已经在抽象类中设置了,所有的具体类都继承了它。

我想过:

  1. 在抽象类中创建另一组配置值,但这似乎会创建重复项,但是当将来还有第三组配置值时,这不是很可扩展。

  2. 将抽象类中配置值的可访问性从私有更改为受保护,并让具体类覆盖它。但我不确定这种覆盖是否好,因为它似乎对实际配置值是什么造成了混淆。

  3. 创建另一个类似于“AbstractService”的抽象类,但使用@Value 注入不同的配置值集。这似乎也造成了重复。

    public abstract class AbstractService {
    
      @Value("${config1}")
      private String config1;  
    
      @Value("${config2}")
      private String config2;    
    
      public void serviceMethod() {
        //using config1 and config 2 values
      }
    }
    
    public class concreteServiceA extends AbstractService {
    
      public void serviceA() {
      // using serviceMethod in the abstract class
      }
    }
    
    public class concreteServiceB extends AbstractService {
    
      public void serviceB() {
        // using serviceMethod in the abstract class
      }
    }
    

如果在抽象类中使用构造函数传递所需参数,并让具体类使用构造函数注入和@Value来设置这些值,这是不是一个好方法?但如果有很长的配置值列表,这可能无法很好地扩展。

public abstract class AbstractService {
  private String config1;
  private String config2;

  public AbstractService(String config1, String config2) {
    this.config1 = config1;
    this.config2 = config2;
  }

  public void serviceMethod() { 
    //using config1 and config2 values
  }  
}

public concreteServiceA extends AbstractService {

  public concreteServiceA(@Value("${config1}") String config1, 
    @Value("${config2}") String config2) {
    super(config1, config2);
  }

  public void serviceA() { 
    //using serviceMethod in the abstract class
  }
}

public concreteServiceB extends AbstractService {
    
      public concreteServiceB(@Value("${configB1}") String config1, 
        @Value("${configB2}") String config2) {
        super(config1, config2);
      }
    
      public void serviceB() { 
        //using serviceMethod in the abstract class
      }
    }

3 个答案:

答案 0 :(得分:1)

您可以像这样使用 setter 注入或(可能更优雅的)构造函数注入:

public abstract class AbstractService {

    protected AbstractService(String config1, String config2) {
        this.config1 = config1;
        this.config2 = config2;
    }

    private String config1;

    private String config2;

    public void serviceMethod() {
        //using config1 and config 2 values
    }
}

public class ConcreteServiceA extends AbstractService {

    public ConcreteServiceA(@Value("${config1a}") String config1, @Value("${config2a}") String config2) {
        super(config1, config2);
    }


    public void serviceA() {
        // using serviceMethod in the abstract class
    }
}

public class ConcreteServiceB extends AbstractService {

    public ConcreteServiceB(@Value("${config1b}") String config1, @Value("${config2b}") String config2) {
        super(config1, config2);
    }


    public void serviceB() {
        // using serviceMethod in the abstract class
    }
}

但是如果你有很多值,你也可以使用 setter 注入并覆盖每个子类中的 setter。或者您仍然可以使用构造函数注入,但传递一个包含如下配置的容器类:

public class ServiceConfig {
    private String config1;
    private String config2;
    // getters, setters and more properties
}

然后这样传

public abstract class AbstractService {
    private ServiceConfig config;
    
    protected AbstractService(ServiceConfig config) {
        this.config = config;
    }
}

public class ConcreteServiceA extends AbstractService {

    public ConcreteServiceA(@Value("${configA}") ServiceConfig config) {
        super(config);
    }
}

答案 1 :(得分:0)

你可以像下面这样:

public abstract class AbstractService {    

    public void serviceMethod() { 
        String config1 = getConfig1();
        String config2 = getConfig2();
        //using config1 and config 2 values 
    }

    public abstract String getConfig1();

    public abstract String getConfig2();
    
}

public class concreteServiceA extends AbstractService {
    @Value("${config1}") private String config1;

    @Value("${config2}") private String config2;

    public String getConfig1(){
        return config1;
    }

    public String getConfig2(){
        return config2;
    }

    public void serviceA() { // using serviceMethod in the abstract class } 
    
}

public class concreteServiceB extends AbstractService {
    @Value("${config1.1}") private String config1;

    @Value("${config2.1}") private String config2;

    public String getConfig1(){
        return config1;
    }

    public String getConfig2(){
        return config2;
    }

    public void serviceB() { // using serviceMethod in the abstract class }
    
}

答案 2 :(得分:0)

您可以将您的属性外部化为特定的 bean,这些 bean 将自动装配到具体的类。

Spring 注释 @ConfigurationProperties 允许您根据属性前缀初始化简单的 POJO 属性。

首先创建您的 POJO,我们将注入具体服务:

public class ServiceProperties {

    private String config1;
    private String config2;

    //getters and setters
}

然后在spring扫描的包中创建一个配置类:

@Configuration
public class ServicePropertiesConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "service-a")
    public ServiceProperties serviceAProperties() {
        return new ServiceProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "service-b")
    public ServiceProperties serviceBProperties() {
        return new ServiceProperties();
    }

}

如您所见,prefix 告诉 spring 他必须在哪里搜索属性。您的 application.properties 将如下所示:

service-a.config1=serviceAConfig1
service-a.config2=serviceAConfig2
service-b.config1=serviceBConfig1
service-b.config2=serviceBConfig2

在这个阶段,你会有两个 ServiceProperties 类型的 bean,里面有特定的值

抽象服务如下所示:

public abstract class AbstractService {

    private final ServiceProperties serviceProperties;

    protected AbstractService(ServiceProperties serviceProperties) {
        this.serviceProperties = serviceProperties;
    }

    public void serviceMethod() {
        //using config1 and config 2 values
//        serviceProperties.getConfig1();
//        serviceProperties.getConfig2();
    }
}

在具体的服务中,你必须使用@Qualifier注解和创建的bean的名字

@Service
public class ConcreteServiceA extends AbstractService{

    public ConcreteServiceA(@Qualifier("serviceAProperties") ServiceProperties serviceProperties) {
        super(serviceProperties);
    }
}


@Service
public class ConcreteServiceB extends AbstractService{

    protected ConcreteServiceB(@Qualifier("serviceBProperties") ServiceProperties serviceProperties) {
        super(serviceProperties);
    }
}
相关问题