如何在无状态服务中编写带有可变参数的模板进程?

时间:2014-03-12 15:57:44

标签: java spring design-patterns

我想写一个总是执行预定义例程的模板类。一种方法是抽象的,因此实现类可以定义对象的自定义处理操作。

班级必须严格无国籍。没有参数可以保存。

@Service
abstract class BaseService {
    void invoke(DataVO data) {
        prepare(data);
        Response rsp = process(data);
        validate(rsp);  
    }

    void prepare(DataVO data) {
        //general data preparation
    }

    void validate(Response rsp) {
        //general validation
    }

    //each implementation can provide custom processor
    abstract Response process(DataVO);
}

我想这样用:

//从套接字获取数据的服务

@Service
class MySocket {
    @Autowired
    private List<BaseService> services;

    public income(InputStream stream) {
        //convert stream to data objects, eg DataVO, CustomerVO based on the input

        //then find d
        action = getActionType(stream);
        for (BaseService service : services) {
            if (service.canHandle(action)) {
                service.invoke(dataVO);
                //sometime, based on the action, provide additional params like CustomerVO etc
            }
        }
    }
}

问题:有时我想要实现,在process()方法中使用2-3个参数,例如process(DataVO, CustomerVO, int)。使用上面的代码当然不可能。但是我怎么能重写这个以便执行模板方法,并且只执行带有变量参数的进程方法?

3 个答案:

答案 0 :(得分:1)

这是一个非常简单和抽象的解决方案。首先,我们定义一个ServiceContext类作为基类,用于保存稍后在服务实现中使用的所有引用(它基本上是一个DTO)。

class ServiceContext {
    // ...
}

服务可以根据需要扩展此基类,以便他们可以定义自己的上下文子类:

class SpecificServiceContext extends ServiceContext {

    // This service only needs a DataVO object
    private DataVO data;

}

当客户端代码在注册服务中迭代时选择服务时,它可以创建一个上下文对象,其中包含所需内容的引用。请注意,这里的service.getContext()只是一个例子来说明它是如何工作的。

@Service
class MySocket {

    // ...

    public income(InputStream stream) {

        // ...

        for (BaseService service : services) {
            if (service.canHandle(action)) {

                // Here, getContext() returns a subclass of ServiceContext 
                // that holds the service specific objects 
                // (in this example dataVO)
                ServiceContext context = service.getContext();

                service.invoke(context);

            }
        }
    }
}

BaseService在不了解实际服务或类型的情况下完成了旧工作。

@Service
abstract class BaseService {

    void invoke(ServiceContext context) {

        // ...
        Response rsp = process(context);
        // ...

    }

    abstract Response process(ServiceContext context);
}

最后,BaseService子类可以使用我们之前封装的上下文来定义任意行为。

@Service
class SpecificService extends BaseService {

    Response process(ServiceContext context) {
        SpecificServiceContext specificContext = (SpecificServiceContext) context;

        // Here, we can do whatever we want. Wow. Much happy. 

    }
}

答案 1 :(得分:0)

只需创建方法调用的新定义

void invoke(DataVO data, CustomerVO customer, int i) {
    prepare(data);
    Response rsp = process(data, customer, i);
    validate(rsp);  
}

和方法流程一起出现:

//each implementation can provide custom processor
abstract Response process(DataVO data, CustomerVO customer, int i);

答案 2 :(得分:0)

您可以制作包含流程可能需要的所有数据的Data Transfer Object

class ServiceDTO{

    public DataV0 getDataV0(){
        ...
    }

    public CustomerV0 getCustomerV0(){
        ...
    }
    ...etc

}

现在,您的流程方法采用ServiceDTO

类型的单个参数
abstract Response process(ServiceDTO);


public income(InputStream stream) {
    //convert stream to DTO based on the input
    ServiceDTO dto = ...

    //then find d
    action = getActionType(stream);
    for (BaseService service : services) {
        if (service.canHandle(action)) {
            service.invoke(dto);
        }
    }
}

关于这一点的好处是过程方法永远不会改变。如果您需要添加更多要处理的内容,可以向新的DTO类添加方法。旧代码不会破坏,因为它不会调用新方法,方法签名保持不变。