java函数接口_Java函数接口实现函数组合及装饰器模式

摘要: 通过求解 (sinx)^2 + (cosx)^2 = 1 的若干写法,逐步展示了如何从过程式的写法转变到函数式的写法,并说明了编写“【接受函数参数】并返回【能够接受函数参数的函数】的【高阶函数】”的一点小技巧。

难度: 中级。

代码在此,先领会一下~~

package zzz.study.function.decrator;

import java.util.Arrays;

import java.util.List;

import java.util.function.BiFunction;

import java.util.function.Function;

import static java.lang.Math.*;

/**

* Created by shuqin on 17/6/29.

*/

public class FunctionImplementingDecrator {

public static void main(String[] args) {

// 求解 (sinx)^2 + (cosx)^2 = 1 的若干写法

double x= 30;

System.out.println(Math.pow(sin(x),2) + Math.pow(cos(x), 2));

System.out.println(pow(Math::sin, 2).apply(x) + pow(Math::cos, 2).apply(x));

double res = op(pow(Math::sin, 2).apply(x), pow(Math::cos, 2).apply(x)).apply((a,b) -> a+b);

System.out.println(res);

double res2 = op(pow(Math::sin, 2), pow(Math::cos, 2), x).apply((a,b) -> a+b);

System.out.println(res2);

Function sumSquare = op(pow(Math::sin, 2), pow(Math::cos, 2)).apply((a,b)->a+b);

System.out.println(sumSquare.apply(x));

Function another = op(compose((d)->d*d, Math::sin), compose((d)->d*d, Math::cos)).apply((a,b)->a+b);

System.out.println(another.apply(x));

Function third = compose(d->d*d, d->d+1, d->d*2, d->d*d*d); // (2x^3+1)^2

System.out.println(third.apply(3d));

}

/** 将指定函数的值封装幂次函数 pow(f, n) = (f(x))^n */

public static Function pow(final Function func, final int n) {

return x -> Math.pow(func.apply(x), (double)n);

}

/** 对给定的值 x,y 应用指定的二元操作函数 */

public static Function, T> op(T x, T y) {

return opFunc -> opFunc.apply(x, y);

}

/** 将两个函数使用组合成一个函数,这个函数接受一个二元操作函数(eg +, -, * , /) */

public static Function, T> op(Function funcx, Function funcy, T x) {

return opFunc -> opFunc.apply(funcx.apply(x), funcy.apply(x));

}

/** 将两个函数组合成一个叠加函数, compose(f,g) = f(g) */

public static Function compose(Function funcx, Function funcy) {

return x -> funcx.apply(funcy.apply(x));

}

/** 将若干个函数组合成一个叠加函数, compose(f1,f2,...fn) = f1(f2(...(fn))) */

public static Function compose(Function... extraFuncs) {

if (extraFuncs == null || extraFuncs.length == 0) {

return x->x;

}

return x -> Arrays.stream(extraFuncs).reduce(y->y, FunctionImplementingDecrator::compose).apply(x);

}

public static Function, Function> op(Function funcx, Function funcy) {

//return opFunc -> { return aT -> opFunc.apply(funcx.apply(aT), funcy.apply(aT)); };

return opFunc -> aT -> opFunc.apply(funcx.apply(aT), funcy.apply(aT));

/* Equivalent to

return new Function, Function>() {

@Override

public Function apply(

BiFunction opFunc) {

return new Function() {

@Override

public T apply(T aT) {

return opFunc.apply(funcx.apply(aT), funcy.apply(aT));

}

};

}

};*/

}

}

编写“【接受函数参数】并返回【能够接受函数参数的函数】的【高阶函数】”的一点小技巧:直接用 lambda 表达式的角度去思考,辅以数学推导。

比如要编写一个函数 F(G,H) , 接受两个一元函数参数 G(x) , H(x) ,返回一个函数: R(op) ,R(op) 接受一个二元操作函数 op(x,y),返回一个一元函数 T(x)。即:F(G(x), H(x)) = R(op)(x) = op(G, H)(x) = T(x) : x -> op(G(x), H(x))

看上去挺绕的!那么该怎么写呢?

先理一理: R(op)(x) = G(x) op H(x) = op(G, H)(x) 。由于 R(op) 是接受一个二元操作函数 opFunc, 那么应该有 opFunc -> opFunc(G, H) ; 完成了一半! 注意到,opFunc(G,H) 的结果应当是一个单元函数 T(x) ,opFunc(G,H) = x -> T(x) , T(x) = op(G(x), H(x)) ; 于是最终有 F(G(x), H(x)) = opFunc -> { x -> opFunc(G(x), H(x)) }

public static Function, Function> op(Function funcx, Function funcy) {

return opFunc -> { return aT -> opFunc.apply(funcx.apply(aT), funcy.apply(aT)); };

}

只要是赋值给函数接口,一定有 (x1,x2,...,xn) -> F(x1,x2,...,Xn) 形式。 然后无非是这种形式的组合及嵌套。 经过一通脑筋急转弯之后,似乎摸到了一点窍门。化简成 lambda 表达式的形式是(IDE会自动提示):

public static Function, Function> op(Function funcx, Function funcy) {

return opFunc -> aT -> opFunc.apply(funcx.apply(aT), funcy.apply(aT));

}

第一种形式更容易理解, 第二种形式比较简洁。显然, -> 符号是右结合优先的。

由此可见,函数式编程可以通过凝练的代码形式将函数能力组合起来,构建强大的抽象表达能力,对于消除重复代码及框架设计有很大的益处。同时,使用函数编程需要经常从“函数及组合的层面”去思考计算,而不是从通常的“求值层面”去思考计算。这无疑对抽象思维能力有更高的要求。

不是每个知识点都要正儿八经地写上一篇文章,多尝试摸索窍门反而是妙法 😃

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
装饰器模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。在装饰器模式中,这些封装对象称为装饰器。 在 Java 中,装饰器模式通常用于动态地修改对象的运行时行为,而不是在编译时就静态地修改代码。这种模式可以让你在不改变一个对象的前提下给其增新的功能。 具体实现时,装饰器类和被装饰类通常都实现同一个接口或继承同一个父类,这样可以保证它们之间的互换性。 下面是一个简单的示例代码: ```java interface Component { void operation(); } class ConcreteComponent implements Component { public void operation() { System.out.println("ConcreteComponent.operation()"); } } class Decorator implements Component { private Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } } class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } public void operation() { super.operation(); System.out.println("ConcreteDecoratorA.operation()"); } } class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } public void operation() { super.operation(); System.out.println("ConcreteDecoratorB.operation()"); } } public class Main { public static void main(String[] args) { Component component = new ConcreteComponent(); component = new ConcreteDecoratorA(component); component = new ConcreteDecoratorB(component); component.operation(); } } ``` 输出结果为: ``` ConcreteComponent.operation() ConcreteDecoratorA.operation() ConcreteDecoratorB.operation() ``` 这个示例中,`Component` 接口定义了一个 `operation()` 方法,`ConcreteComponent` 类实现了这个接口并提供了具体的实现。`Decorator` 类也实现了 `Component` 接口,并在其构造函数中接收一个 `Component` 对象,它的 `operation()` 方法会调用被装饰对象的 `operation()` 方法。`ConcreteDecoratorA` 和 `ConcreteDecoratorB` 类都继承自 `Decorator` 类,并在其 `operation()` 方法中先调用父类的 `operation()` 方法,再添自己的行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值