java开放封闭原则,适用于多种服务

时间:2017-04-14 11:19:08

标签: java generics inheritance interface

我想说我想定义一个代表远程服务调用的接口。

两种服务都有不同的请求和响应

public interface ExecutesService<T,S> {
    public T executeFirstService(S obj);
    public T executeSecondService(S obj);
    public T executeThirdService(S obj);
    public T executeFourthService(S obj);
}

现在,让我们看一下实现

public class ServiceA implements ExecutesService<Response1,Request1>
{
  public Response1 executeFirstService(Request1 obj)
  {
    //This service call should not be executed by this class
    throw new UnsupportedOperationException("This method should not be called for this class");
  }

  public Response1 executeSecondService(Request1 obj)
  {
    //execute some service
  }

   public Response1 executeThirdService(Request1 obj)
  {
    //execute some service
  }

   public Response1 executeFourthService(Request1 obj)
  {
    //execute some service
  }
}


public class ServiceB implements ExecutesService<Response2,Request2>
{

 public Response1 executeFirstService(Request1 obj)
  {
    //execute some service
  }

  public Response1 executeSecondService(Request1 obj)
  {
      //This service call should not be executed by this class
    throw new UnsupportedOperationException("This method should not be called for this class");
  }

   public Response1 executeThirdService(Request1 obj)
  {
      //This service call should not be executed by this class
    throw new UnsupportedOperationException("This method should not be called for this class");
  }

   public Response1 executeFourthService(Request1 obj)
  {
    //execute some service
  }
}

在另一个类中,取决于请求中的某些值,我创建了ServiceAServiceB的实例

我对上述内容有疑问:

在您想要提供需要不同ExecutesService<T,S>Request的子类的情况下,使用通用接口Response是否合适。

如何更好地完成上述工作?

4 个答案:

答案 0 :(得分:1)

我认为实现接口并使调用不支持的方法成为可能并不是一个好主意。这是一个标志,您应该根据具体情况将接口拆分为两个或三个,这样每个类都实现了已实现接口的所有方法。

在您的情况下,我会将整个界面拆分为 ,使用继承来避免加倍。请看示例:

public interface ExecutesService<T, S> {
    T executeFourthService(S obj);
}

public interface ExecutesServiceA<T, S> extends ExecutesService {
    T executeSecondService(S obj);
    T executeThirdService(S obj);    
}

public interface ExecutesServiceB<T, S> extends ExecutesService {
    T executeFirstService(S obj);
}

请注意,在接口方法中放置public修饰符是多余的。

希望这有帮助。

答案 1 :(得分:1)

如果您知道在某种情况下,接口的大部分方法都不受支持,那么拥有接口并不是真的有意义,所以客户端不应该调用它。 为什么要向客户端提供可能容易出错的接口?
我认为你的用例中应该有两个不同的API,即两个类(如果不再需要接口)或两个接口。

但是,这并不意味着两个API不能共享一个共同的接口祖先,如果它对某些处理有意义,其中实例应该可以互换,因为它们依赖于相同的操作契约。

  

在这种情况下是否使用通用interace(ExecutesService)   您想在哪里提供需要不同Request的子类   和回应。

这不是经典类派生,但在某些情况下它是可取的 它允许对具有足够类似方法但在签名中不使用相同返回类型或参数类型的实现使用通用接口:

public interface ExecutesService<T,S>

它允许定义经典派生不能的契约。

但是,这种实现类的方式不允许按接口编程,因为声明的类型指定了特定的类型:

ExecutesService<String, Integer> myVar = new ExecutesService<>();

不能互换:

ExecutesService<Boolean, String> otherVar

就像myVar = otherVar

我认为你的问题是一个相关问题 您操纵具有足够接近的方法但实际上不是相同行为的实现 所以,你完成了两个与它们之间没有关系的概念的混合。

通过使用经典继承(没有泛型),您可能会引入非常快速的不同接口。

答案 2 :(得分:1)

我建议你创建两个不同的接口,每个接口都处理自己的请求和响应类型。 当然,您可以使用一个处理所有逻辑的通用接口开发实现,但从我的角度来看,它可能会使代码更复杂和更脏。 问候

答案 3 :(得分:1)

基本上,您的当前设计违反open closed principle ,即如果您想将executeFifthService()方法添加到ServiceAServiceB等,该怎么办?类。

更新所有服务A,B等类别并不是一个好主意,简单来说,类应该为扩展而打开但是关闭以进行修改

相反,您可以参考以下方法:

执行服务界面:

public interface ExecutesService<T,S> {
    public T executeService(S obj);
}

ServiceA类:

public class ServiceA implements ExecutesService<Response1,Request1> {

    List<Class> supportedListOfServices = new ArrayList<>();
    //load list of classnames supported by ServiceA during startup from properties

    public Response1 executeService(Request1 request1, Service service) {
        if(!list.contains(Service.class)) {
           throw new UnsupportedOperationException("This method should 
                      not be called for this class");
        } else {
            return service.execute(request1);
        }
    }
}

同样,您也可以实施ServiceB

服务界面:

public interface Service<T,S> {
    public T execute(S s);
}

FirstService类:

public class FirstService implements Service<Request1,Response1> {
    public Response1 execute(Request1 req);
}

同样,您还需要实施SecondServiceThirdService等。

所以,在这种方法中,你基本上是在运行时传递Service(实际上被调用,可能是FirstServiceSecondService等)。{{1 }}验证它是否在ServiceA,如果不是supportedListOfServices

重要的一点是,您无需更新任何现有服务即可添加新功能(与您需要在UnsupportedOperationException中添加executeFifthService()的设计不同,{{1}等等..),而你需要再添加一个名为ServiceA的类并传递它。