请问这种逻辑特别简单,但是写起来非常蛋疼的 Java 怎么办?

2017-12-05 11:10:21 +08:00
 20015jjw

我知道各位会说换其他 Java 替代语言(Kotlin...),但是公司代码库暂时不支持。

现在我有一堆User, 然后有个 Helper 会逐个检查这些 User,然后如果 User 的 Email 地址或者电话号码对应输入,就 return 那个 User。代码如下(手工重写的,省去了很多细节)

public User getUserFromEmail(String email) {
  for (User user : getUsers()) {
    if (email.equals(user.getEmail())) {
      return user;
    }
  } 
}

public User getUserFromPhoneNumber(String phoneNumber) {
  for (User user : getUsers()) {
    if (phoneNumber.equals(user.getPhoneNumber())) {
      return user;
    }
  } 
}

那这俩方程基本就差一点点,所以我想把他们合并起来。我现在的想法写出来感觉非常恶心。

public User getUserFromEmail(String email) {
  User(email, null);
}

public User getUserFromPhoneNumber(String phoneNumber) {
  getUser(null, phoneNumber);
}

private User getUser(String email, String phoneNumber) {
  String query, userInfo;
  if (email != null) {
    query = email;
  } else if (phoneNumber != null) {
    query = phoneNumber;
  } else {
    return null;
  }
  for (user : getUsers()) {
    if (email != null) {
      userInfo = user.getEmail();
    } else if (phoneNumber != null) {
      userInfo = user.getPhoneNumber();
    }
    if (query.equals(userInfo)) {
      return user;
    }
  }
}

蛋疼的地方有 2 个,一个是合并后结果比原来长很多,还有一个是这样每个循环都要做多一个 check,显得非常愚蠢,不知道各位 Java 大佬有没有什么办法可以帮到我,先谢谢了 ><

2424 次点击
所在节点    问与答
19 条回复
hyyou2010
2017-12-05 11:52:17 +08:00
定义这么个东西:
public class UserCompareItems{
public String name;//为 null 时表示不必对这一项
public String phone;//非 null 时表示比对这一项
public String otherItems;
}

然后在 User 类中实现一个和 UserCompareItems 比较的接口
以后只传这个类的对象来挑选 user

----------临时想的,没验证,不一定好,仅供参考
cloud107202
2017-12-05 11:52:48 +08:00
这个算是 OO 语言给思维带来的枷锁。试图从 List 中 filter 一些结果,但是要根据不同的动态条件。纯 OO 语言里不太好做,或者需要动用设计模式。FP 里就是把怎样取属性并比较这个动作(function/ first-class function ) 当成变量传进去而已。

举个例子,边界判断要自己补充下
https://gist.github.com/liyuntao/54bc04e963fa969b2d82903d51bfea69
SuperMild
2017-12-05 12:16:21 +08:00
电话号码不可能含 @ ,判断一下字符就可以自动选择不同的流程了
SuperMild
2017-12-05 12:18:44 +08:00
增加一个叫 getFromEmailOrPhonenumber 的 wraper
20015jjw
2017-12-05 12:26:42 +08:00
@cloud107202
你的想法我挺喜欢,但是 Java 还不支持,所以很痛苦... 我大概实现了一个类似的,但是无奈效果还是感觉不如原来的,因为还是比原来的长,而且比原来的难读很多。谢谢了。
@hyyou2010 welp,简直蛋疼... 如果就 email 和电话感觉远不要这么麻烦。
marknote
2017-12-05 12:29:38 +08:00
用 lambda 吧
20015jjw
2017-12-05 12:30:48 +08:00
@SuperMild 我也想到了,但感觉虽然这里可以用,但是换一种情况就又蛋疼了... 而且还是少不了每次循环的电话 /邮箱 check...

```
for (...) {
if (query.is_number && query.equals(User.getPhoneNumber()) {
return user;
} else if (query.is_email && query.equals(User.getEmail()) {
return user;
}
}
```
canbingzt
2017-12-05 13:01:57 +08:00
直接 query.equals(user.getEmail()) || query.equals(user.getPhoneNumber()) 就可以了吧
邮箱和电话号码应该不会相同吧
zjp
2017-12-05 13:18:13 +08:00
如果还有更多属性需要查找,#2 的行为模版化的方法就能体现出优势来 只是没有 lambda 写起来更长了…
cloud107202
2017-12-05 13:22:22 +08:00
@20015jjw 给你的代码就是 java8 的 lambda API...
SoloCompany
2017-12-05 13:25:15 +08:00
实在用不了 j8 还可以用 org.apache.common-collections 顶一下,别想可以有多大改进,只是换一种抽象( functor 或说算子)而已
kran
2017-12-05 13:37:38 +08:00
用反射,传字段名和值
ssynhtn
2017-12-05 14:44:36 +08:00
自定义一个 Interface
interface Matcher {
boolean matches(User user);
}

通用方法
User getUser(Matcher matcher) {
for (User user : getUsers()) {
if (matcher.matches(user) return user;
}
return null;
}

这是很基本的东西, 上面有人说用 lamda 也好用 stream api 的 filter 也好都是同一个道理
这种东西在 Java 里面到处都有
LxExExl
2017-12-05 14:51:39 +08:00
没写过 java
PHP 的话有 schema 直接 queryFrom 然后 whereEquals...

帮顶了
evitceted
2017-12-05 15:13:16 +08:00
rxjava
20015jjw
2017-12-05 17:19:44 +08:00
@cloud107202 我的意思是 java 8 不能用 很难受...
@ssynhtn 对这个也很难读 我想到了但是写出来不可能比那俩原方程短了
@SoloCompany 一会看看 谢谢 但是我觉得可能 @canbingzt 的办法暂时就够了 没想到这个 hhhh 谢谢啦
yrom
2017-12-05 17:25:41 +08:00
android studio 3.0 已经支持 java 8 部分特性了(尤其是 lambda )
YellowLittleDog
2017-12-05 18:20:22 +08:00
rxjava 链起来
20015jjw
2017-12-06 00:52:38 +08:00
@yrom 我们的 codebase 不支持...
@YellowLittleDog ...那也太麻烦了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/412085

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX