【问题标题】:java open closed principle for multiple servicesjava多服务的开闭原理
【发布时间】:2017-04-14 11:19:07
【问题描述】:

假设我想定义一个接口来表示对远程服务的调用。

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

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 的实例

我对上述内容有疑问:

在您想要提供需要不同RequestResponse 的子类的情况下,使用通用接口ExecutesService&lt;T,S&gt; 是否合适。

我怎样才能更好地做到以上几点?

【问题讨论】:

    标签: java generics inheritance interface


    【解决方案1】:

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

    更新所有服务 A、B 等并不是一个好主意。简单地说,类应该对扩展开放但对修改关闭

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

    ExecutesService 接口:

    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 等),ServiceA 验证它是否在@ 987654336@,如果没有,则抛出 UnsupportedOperationException

    这里的重点是,您无需更新任何现有服务即可添加新功能(与您的设计不同,您需要在ServiceAB 等中添加executeFifthService()) ,而是需要再添加一个名为 FifthService 的类并通过它。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        如果您知道在一种情况下,接口的大多数方法都不支持,因此不应由客户端调用,那么拥有接口就没有真正意义。
        为什么要向客户提供一个容易出错的界面?
        我认为您的用例中应该有两个不同的 API,即两个类(如果不再需要接口)或两个接口。

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

        在使用泛型接口(ExecutesService)的情况下好不好 您想在哪里提供需要不同请求的子类 和响应。

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

        public interface ExecutesService<T,S>
        

        它允许定义经典推导无法定义的合约。

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

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

        不能与 :

        互换
        ExecutesService<Boolean, String> otherVar
        

        喜欢myVar = otherVar

        我认为你的问题是一个相关的问题。
        您操作的实现具有足够接近的方法,但行为并不完全相同。
        因此,您完成了将两个概念中没有关系的事物混合在一起。

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

        【讨论】:

          【解决方案4】:

          我想实现接口并允许调用不受支持的方法不是一个好主意。这是一个标志,你应该根据具体情况将你的接口分成两个或三个,这样每个类都实现了实现接口的所有方法。

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

          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 修饰符是多余的。

          希望这会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-05-03
            • 2015-02-05
            • 2013-02-27
            • 2013-06-15
            相关资源
            最近更新 更多