按照 Venkat Subramaniam 的书使用 lambda 表达式玩策略设计模式?

问题描述

我正在关注 Subramaniam 教授的 book。在书中教授试图解释Delegating Using Lambda Expressions的原理。

我们使用 lambda 表达式和策略模式来分隔一个 来自方法的关注。我们还可以使用它们将关注点与 一类。从重用的角度来看,委托是一种更好的设计 工具而不是继承。通过委托,可以更容易地改变 我们依赖的实现,我们可以插入不同的行为 更动态。这可以帮助改变类的行为 独立于它们所依赖的部分的行为,并使 设计更灵活,无需强制使用很深的类层次结构

这是一个带有静态方法的特定类,它执行所需的信息计算/获取

 public class YahooFinance {
        public static BigDecimal getPrice(final String ticker) {
            try {
                final URL url = new URL("http://ichart.finance.yahoo.com/table.csv?s=" + ticker);
                final BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
                final String data = reader.lines().skip(1).findFirst().get();
                final String[] dataItems = data.split(",");
                return new BigDecimal(dataItems[dataItems.length - 1]);
            } catch(Exception ex) {
                throw new RuntimeException(ex);
            }
        }
  }

Creating a Delegate: 与其将部分责任委托给另一个类,我们可以将它委托给 lambda 表达式和方法引用。这将进一步减少类的扩散。

这是客户端代码(即 Delegate):

public class CalculateNAV {
    

    private Function<String,BigDecimal> priceFinder;
    
      public CalculateNAV(final Function<String,BigDecimal> aPriceFinder) {
          priceFinder = aPriceFinder;
      }

      public BigDecimal computeStockWorth(final String ticker,final int shares) {
    
          return priceFinder.apply(ticker).multiply(BigDecimal.valueOf(shares));
      }
  //... other methods that use the priceFinder ...


  public static void main(String[] args) {
    final CalculateNAV calculateNav = new CalculateNAV(YahooFinance::getPrice);
    
    System.out.println(String.format("100 shares of Google worth: $%.2f",calculateNav.computeStockWorth("GOOG",100)));
  }
}

我的领域问题在某种程度上与教授想要做的非常相似。

我的 Spring 应用程序中有三个实体(InvoicetourInvoiceLabTestInvoicePenatly)。它们具有不同的属性并且没有任何关系,因此没有继承,没有接口。但我确实需要将它们发送到某个 SOAP Web 服务,该服务将为这些实体中的每一个返回相同的对象类型 (InsertInvoiceResponse)。 SoapHelper 类很像 YahooFinance

public class SoapHelper {
    
    public InsertInvoiceResponse getValueForTour(Invoicetour invoicetourEntity,Company company) {

        //Some processing of passed parameters which results in InsertInvoiceRequest (requestPayload) object (stub for soap service)

        return send(requestPayload);
    }

    public InsertInvoiceResponse getValueForLabTest(InvoiceLabTest invoiceLabTestEntity,Company company) {

        //Some processing of passed parameters which results in InsertInvoiceRequest (requestPayload) object (stub for soap service)

        return send(requestPayload);
    }

    public InsertInvoiceResponse getValueForPenalty(InvoicePenalty invoicePenalty Entity,Company company) {

        //Some processing of passed parameters which results in InsertInvoiceRequest (requestPayload) object (stub for soap service)

        return send(requestPayload);
    }
}

方法send(requestPayload)是这样的:

//Spring's abstraction for sending SOAP requests
public InsertInvoiceResponse send(InsertInvoiceRequest requestPayload) {
    return (InsertInvoiceResponse) getwebservicetemplate()
    .marshalSendAndReceive("https://clienttesthorizon.horizonafs.com/AFSServices/AFSService.svc/basicHttpBinding",requestPayload,new SoapActionCallback("http://tempuri.org/IAFSService/InsertInvoice")); 
}

我做了什么?

首先我创建了函数式界面,如下所示:

@FunctionalInterface
public interface Executor<A,B,C> { //A - stands for any InvoiceXXX; B - Company parameter and C will be result of soap response (InsertInvoiceResponse)
    
    C apply(A a,B b);
}

接下来,我创建了一个类,它负责使用方法引用调用实际的方法实现。 SoapCaller 类很像 CalculateNAVSoapCaller 将具有 Executor 类型的私有字段,但我想让它更通用。我确实明白接口本身已经是通用的,但由于缺乏语言,我不确定如何表达不同。

我的想法是能够像这样传递给 SoapCaller 的构造函数

   public class SoapCaller {
    
        private Executor<A,C> exec;
        
        public SoapCaller(final Executor<Class<T> t,Class<F> f,Class<E> e> execGeneric) {
            this.exec = execGeneric;
        }
        
        public InsertInvoiceResponse callWebService(Class<T> t,Class<F> f) {
            
          return exec.apply(t,f);
        }
        
    }

我的客户端代码应该是这样的:

public static void main(String[] args) {
    
    Invoicetour it = db.getInvoicetour();
    InvoiceLabTest ilt = db.getInvoiceLabtest();
    InvoicePenalty ip = db.getInvoicePenalty();
    
    Company c = db.getCompany();
    
    SoapCaller soapCallerForInvoicetour = new SoapCaller(SoapHelper::getValueForTour);
    
    InsertInvoiceResponse invoicetourResponse = soapCallerForInvoicetour.callWebService(it,c);
    
    //do what ever with invoicetourResponse
    
    SoapCaller soapCallerForInvoiceLabTest= new SoapCaller(SoapHelper::getValueForLabTest);
    
    InsertInvoiceResponse invoiceLabTestResponse = soapCallerForInvoicetour.callWebService(ilt,c);
    
    //do what ever with invoiceLabTestResponse
    
}

当然,有编译错误的语气。我不确定如何实现使功能接口更通用然后它已经是(如果这有任何意义)?有没有人知道如何使用 lambdas 和方法引用使其更具可读性?

解决方法

如果我理解你,你希望 SoapCaller(委托给 lambda 的类)也是泛型的,所以它可以定义如下:

class SoapCaller<T,U> {

    private BiFunction<T,U,InsertInvoiceResponse> soapExecutor;
    
    public SoapCaller(final BiFunction<T,InsertInvoiceResponse> soapExecutor) {
        this.soapExecutor= soapExecutor;
    }
    
    public InsertInvoiceResponse callWebService(T t,U u) {
      return soapExecutor.apply(t,u);
    }
    
}

请注意,您可以使用 BiFunction 而不是定义自己的功能接口。

那么你就可以这样使用了:

SoapCaller<InvoiceTour,Company> soapCallerForInvoiceTour = new SoapCaller<>(SoapHelper::getValueForTour);
InsertInvoiceResponse invoiceTourResponse = soapCallerForInvoiceTour.callWebService(it,c);
    
//do what ever with invoiceTourResponse
    
SoapCaller<InvoiceLabTest,Company> soapCallerForInvoiceLabTest= new SoapCaller<>(SoapHelper::getValueForLabTest);
InsertInvoiceResponse invoiceLabTestResponse = soapCallerForInvoiceLabTest.callWebService(ilt,c);

您可以使用泛型参数,例如,如果您知道 Company 不会改变,那么您可以删除类型参数:

class SoapCaller<T> {

    private BiFunction<T,Company,InsertInvoiceResponse> soapExecutor;

    ...
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...