Java:让你的代码更整洁:函数式接口

Java:让你的代码更整洁:函数式接口


许多开发人员认为,好代码的重要标志之一就是减少重复代码,甚至还给这个原则起了个特殊的名字:不要重复你自己(DRY)。但是当你写Java代码的时候,有时候做到这一点就不容易。许多情况下我们把长方法分解成更小的代码块(方法),然后重用这些代码,但是这样可能让代码更费解,因为你以一个包含许多小方法的类告终,而且他们之间并没有明确的关系。可以进一步地将提取的函数组成一个函数式接口对象,这样就保持结构,但是这种方式需要用到大量的样板代码。
让我们来看看,怎么使用函数式接口对象,来解决常见的代码重复问题。在下面的例子中,saveUser方法用于将user的信息保存到数据库,并且确保user的对象包含有效数据。

public class User {
    private String ID = null;
    private String name = null;
    private String email = null;
    private String nickname = null;
    ...
    /*省略getter、setter方法*/
    ...
}
public class UserDao {
    public void saveUser(User user) {
        if (user.getID() == null || user.getID().trim().length() == 0) {
            throw new IllegalArgumentException(String.format("Can't save user(ID=%s):%s", user.getID(), "empty ID"));
        }
        if (user.getName() == null || user.getName().trim().length() == 0) {
            throw new IllegalArgumentException(String.format("Can't save user(ID=%s):%s", user.getID(), "empty Name"));
        }
        if (user.getEmail() == null || user.getEmail().trim().length() == 0) {
            throw new IllegalArgumentException(String.format("Can't save user(ID=%s):%s", user.getID(), "empty Email"));
        }
        if (user.getNickname() == null || user.getNickname().trim().length() == 0) {
            throw new IllegalArgumentException(String.format("Can't save user(ID=%s):%s", user.getID(), "empty Nickname"));
        }
        //保存到数据库
        ...
    }
}

这里的重复代码是很少的,你可能不想要在类中的一个面面俱到的方法中,去验证用户字段的每一种特殊情况。但是,如果将验证代码放到函数式接口对象中,可以摆脱重复,并保持清晰的代码结构。可以这样做:

public class UserDao {
    public void saveUser(User user) {
        BiPredicate<String, String> emptyPredicate = (value, message) -> {
            if (value == null || value.trim().length() == 0) {
                throw new IllegalArgumentException(String.format("Can't save user(ID=%s):%s", user.getID(), message));
            }
            return true;
        };
        emptyPredicate.test(user.getID(),"empty ID");
        emptyPredicate.test(user.getName(),"empty Name");
        emptyPredicate.test(user.getEmail(),"empty Email");
        emptyPredicate.test(user.getNickname(),"empty Nickname");
        //保存到数据库中
        ...
    }
}

备注:BiPredicate为Java8的一个函数式接口,其简单源码如下:

public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}

这样看起来好多了,不用重复验证逻辑,如果项目演进是需要向User添加其他字段,也可以轻松添加更多验证。不过我们再看看saveUser方法,发现验证逻辑与saveUser方法没有关系。我们再优化这段代码,使其看起来更整洁:

public class UserDao {
    public void saveUser(User user) {
        UserValicate.validateBeforeSave(user);
        //保存到数据库中
        ...
    }
}

将一段代码提取到工具类中,看起来相当有效。即使User属于当前代码库而不是类库的一部分,你也不会希望这段逻辑放到User的方法中,因为它和其他用到User的地方没有关系。如果你能遵循类的API只能包含必须的方法,那么就可以让类保持精炼的同时,也让你的思路更加清晰。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a.erke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值