[英]Generalize two similar methods that have different unary operators
Suppose I have the following implementations假设我有以下实现
private static String encryptPassword(String password) {
String encryptedPassword = "";
char[] chars = password.toCharArray();
for (char c : chars) {
encryptedPassword = encryptedPassword.concat(String.valueOf(++c));
}
return encryptedPassword;
}
private static String decryptPassword(String encryptedPassword) {
String decryptedPassword = "";
char[] chars = encryptedPassword.toCharArray();
for (char c : chars) {
decryptedPassword = decryptedPassword.concat(String.valueOf(--c));
}
return decryptedPassword;
}
These methods do very simple stuff that it will increase each character in a string by 1 and this process is considered as encryption.这些方法做的事情非常简单,它将字符串中的每个字符增加 1,这个过程被认为是加密。 As a contrast, the process of decryption will decrease the value.相反,解密过程会降低价值。
I can see that these two methods are pretty much the same, except the unary operators.我可以看到这两种方法几乎相同,除了一元运算符。
How can I generalize these two methods?我如何概括这两种方法?
Furthermore, I also prefer streaming processing to looping.此外,我也更喜欢流式处理而不是循环。 If you have any ideas regarding this point please posting as well.如果您对这一点有任何想法,请也发帖。
You can make use of the Java 8 Functional programming features to provide the behavior expressed as a Function as a method argument.您可以使用 Java 8 函数式编程功能来提供表示为 Function 的行为作为方法参数。
Here's how your logic can be implemented using Stream API, the additional argument the method expects is of type IntUnaryOperator
( which is a function expecting a single int
argument, and producing int
value as the result ).下面是如何使用 Stream API 来实现您的逻辑,该方法期望的附加参数是IntUnaryOperator
类型(这是一个 function 期望单个int
参数,并生成int
值作为结果)。
public static String processPassword(String password,
IntUnaryOperator operator) {
return password.chars()
.map(operator)
.collect(
StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append
)
.toString();
}
And here's how you can call this method from the client code:以下是如何从客户端代码调用此方法:
String encrypted = processPassword("fooBar", i -> ++i);
System.out.println(encrypted);
String decrypted = processPassword(encrypted, i -> --i);
System.out.println(decrypted);
Output: Output:
gppCbs
fooBar
But, it's error-prone (for instance, a function with ++i
can be accidentally instead of a function with --i
), and has a maintainability issue because you might end up with repeating these functions in several places, so it would be harder to change them.但是,它容易出错(例如,带有++i
的 function 可能会意外地代替带有 --i 的--i
),并且存在可维护性问题,因为您最终可能会在多个地方重复这些函数,因此它会更难改变它们。
The better approach would be to abstract the client from the actual implementations of the functions used in encrypting/decrypting and store these functions in one place, so that they can be easily modified without effecting the rest of the code.更好的方法是将客户端从加密/解密中使用的函数的实际实现中抽象出来,并将这些函数存储在一个地方,这样就可以很容易地修改它们,而不会影响代码的 rest。
This can be achieved by introducing an enum
.这可以通过引入enum
来实现。
public enum ProcessType {
ENCRYPT(i -> ++i),
DECRYPT(i -> --i);
private IntUnaryOperator operator;
// constructor, getter
}
And we need to modify the method shown above to make it consume an enum constant instead of a function:我们需要修改上面显示的方法,使其使用枚举常量而不是 function:
public static String processPassword(String password,
ProcessType type) {
return password.chars()
.map(type.getOperator())
.collect(
StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append
)
.toString();
}
And that's how the client code would look like:这就是客户端代码的样子:
String encrypted = processPassword("fooBar", ProcessType.ENCRYPT);
System.out.println(encrypted);
String decrypted = processPassword(encrypted, ProcessType.DECRYPT);
System.out.println(decrypted);
Output: Output:
gppCbs
fooBar
Define a enum to specify operaiton type, based on the enum you can apply business logic.定义一个枚举来指定操作类型,基于枚举你可以应用业务逻辑。
private static enum OperationType {
ENCRYPTION(1), DECRYPTION(-1);
int val;
private OperationType(int val) {
this.val = val;
}
}
private static String process(final String data, final OperationType operationType) {
final char[] chars = data.toCharArray();
final StringBuilder builder = new StringBuilder();
for (char ch : chars) {
builder.append(String.valueOf(ch + operationType.val));
}
return builder.toString();
}
To work with streams, you can use string chars method like below.要使用流,您可以使用如下所示的字符串字符方法。
Stream<Character> charStream = data.chars().mapToObj(i->(char)i);
The difference between the two methods encryptPassword
and decryptPassword
is the value that you are adding to each char
in the String
. encryptPassword
和decryptPassword
这两种方法的区别在于您要添加到String
中每个char
的值。 Therefore I suggest adding a third method that takes two parameters: the first is the String
to encrypt (or decrypt) and the second is the value to add to each char
.因此,我建议添加第三种方法,该方法采用两个参数:第一个是要加密(或解密)的String
,第二个是要添加到每个char
的值。 In the below code, I called this third method adjustPassword
.在下面的代码中,我调用了第三种方法adjustPassword
。
As described in the book Java by Comparison I suggest keeping methods encryptPassword
and decryptPassword
and have those methods call method adjustPassword
with the appropriate value.如Java书中所述,我建议保留方法encryptPassword
和decryptPassword
,并让这些方法使用适当的值调用方法adjustPassword
。 That way, when you want to encrypt or decrypt a password, you don't need to remember what value to pass for the required operation.这样,当您想要加密或解密密码时,您无需记住为所需操作传递的值。
Explanations after the code.代码后的解释。
public class Solution {
private static String encryptPassword(String password) {
return adjustPassword(password, 1);
}
private static String decryptPassword(String encryptedPassword) {
return adjustPassword(encryptedPassword, -1);
}
private static String adjustPassword(String password, int adjustment) {
StringBuilder sb = new StringBuilder(password.length());
password.chars()
.map(c -> c + adjustment)
.forEach(i -> sb.append((char) i));
return sb.toString();
}
public static void main(String[] args) {
String password = "George";
System.out.println("Original: " + password);
String encrypted = encryptPassword(password);
System.out.println("Encrypted: " + encrypted);
System.out.println("Decrypted: " + decryptPassword(encrypted));
}
}
Running the above code produces the following output:运行上面的代码会产生以下 output:
Original: George
Encrypted: Hfpshf
Decrypted: George
String
has method chars()
which returns an IntStream
since char
is essentially an int
.由于 Java 9,class String
具有方法chars()
返回IntStream
因为char
本质上是一个int
。StringBuilder
has overloaded append
methods. Class StringBuilder
重载append
方法。 In the forEach
method, the type of the method parameter, ie i
, is int
, hence the cast to char
, otherwise method adjustPassword
would return a String
that only contained digits.在forEach
方法中,方法参数的类型,即i
,是int
,因此转换为char
,否则方法adjustPassword
将返回一个仅包含数字的String
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.