如何按类类型委托服务?

时间:2016-06-21 09:52:32

标签: java design-patterns

我有不同的类类型,并且根据某些条件,我想委托给可以处理这些类类型的相应service

实施例: 我有几个课程如下。

class Student;
class Prof;
...

每个班级都有一项服务,实施:

interface IPersonService {
    void run();
}

我在某些条件下找到了mode

enum PersonType {
    STUDENT, PROF;
}

当我委托时:

@Autowired
private StudentService studentService;

@Autowired
private ProfService profService;

//@param mode assume known
public void delegate(PersonType mode) {

    //assume there are several of those switch statements in my business code
    switch (mode) {
        case STUDENT: studentService.run(); break;
        case PROF: profService.run(); break;
        default: break;
    }
}

问题:在引入其他类时,我必须修改PersonType并添加一个额外的枚举(这没问题),但我还必须扩展任何{{1语句并添加对其他委托服务的调用。此外,我必须将这些服务显式自动装配到交换机委托人。

问题:我如何优化此代码,为任何其他类实现新服务,而不必触及任何switch语句?

3 个答案:

答案 0 :(得分:5)

IPersonService添加一个方法,以便该方法的实现可以告诉程序它处理的人员类型:

interface IPersonService {
    PersonType supportedPersonType();
    void run();
}

在执行委派的服务中,注入一个List<IPersonService>,Spring将填充它可以找到的IPersonService的所有实现。然后实现delegate方法查看列表,找到可以处理特定类型的第一个IPersonService

@Autowired
private List<IPersonService> personServices;

public void delegate(PersonType mode) {
    for (IPersonService personService : personServices) {
        if (personService.supportedPersonType().equals(mode)) {
            personService.run();
            break;
        }
    }
}

这样,您可以添加IPersonService的新实现,而无需更改执行委派的服务。

为避免每次调用delegate时都要经过循环,您可以事先构建Map,以便快速查找正确的IPersonService

class DelegatingService {
    @Autowired
    private List<IPersonService> personServices;

    private Map<PersonType, IPersonService> personServiceMap;

    @PostConstruct
    public void init() {
        personServiceMap = new HashMap<>();
        for (IPersonService personService : personServices) {
            personServiceMap.put(personService.supportedPersonType(), personService);
        }
    }

    public void delegate(PersonType mode) {
        personServiceMap.get(mode).run();
    }
}

(为简单起见省略了错误处理)。

答案 1 :(得分:1)

在我的应用程序中,我们通过将服务放入地图来解决类似的问题。考虑Map<PersonType,IPersonService> serviceMap定义为bean并注入您的类。 然后委托方法简单做

public void delegate(PersonType mode) {
    IPersonService service = serviceMap.get(mode);
    if (service!=null){
        service.run();
    }else{
        //do something if service is null
    }
}

答案 2 :(得分:0)

您可以将服务bean名称(或类类型)存储在枚举中,并使用getBean按名称(或分别按类类型)从应用程序上下文中获取bean。

此外,所有服务都需要实现一个具有run方法的接口。

interface ModeService {
    void run();
    }

    enum PersonType {
        STUDENT("studentService"), PROF("profService");
        private String serviceBean;
        public PersonType(String serviceBean) {
              this.serviceBean = serviceBean);
        }
        public String getServiceBean() {
               return serviceBean;
        }
    }

在委托中,可以使用以下内容。 ((ModeService)applicationContext.getBean(mode.getServiceBean()).run()

这样只需要使用要使用的服务类型更新枚举,并且不需要更改委托方法。