当前位置:网站首页>A piece of code has been refactored six times by the boss, and my mind is broken
A piece of code has been refactored six times by the boss, and my mind is broken
2022-06-11 06:18:00 【Milo_】

List of articles
Preface
Hi, Hello everyone , This is Milo . I'm back
Come in and give you a piece of gossip , Look what I've been doing ? Recently, the company received a new project of agricultural products trading website , Because of a code refactoring problem, I almost got involved with the boss , I thought it was the boss who deliberately made trouble for me . In the end, I found out that I was too busy , It's like this !
At the weekly meeting , The boss told us that we recently received an agricultural products trading platform , It is mainly used for online trading of agricultural products in the whole province . First of all , It's about taking our Gansu Province Yellow river honey Sell it , I was assigned to sell melons ! Ow , No , I'm responsible for developing the function of selling melons ; Soon I designed the following class to define melon Melon class :
/** * melon * @author Milo Lee * @date 2021-04-07 13:21 */
public class Melon {
/** Varieties */
private final String type;
/** weight */
private final int weight;
/** Place of Origin */
private final String origin;
public Melon(String type, int weight, String origin) {
this.type = type;
this.weight = weight;
this.origin = origin;
}
// getters, toString() Method ellipsis
}
After a meal CRUD Operation , I have finished the work of adding, deleting, modifying and checking melons , Hand over work .
for the first time Select melons by type
the second day , The boss asked me a question , It can filter melons by melon type . Isn't that easy ? therefore , So I created a Filters class , Implemented a filterMelonByType Method
/** * @author Milo Lee * @date 2021-04-07 13:25 */
public class Filters {
/** * Select melons by type * @param melons Melon * @param type type * @return */
public static List<Melon> filterMelonByType(List<Melon> melons, String type) {
List<Melon> result = new ArrayList<>();
for (Melon melon: melons) {
if (melon != null && type.equalsIgnoreCase(melon.getType())) {
result.add(melon);
}
}
return result;
}
}
Get it done , So let's test that out
public static void main(String[] args) {
ArrayList<Melon> melons = new ArrayList<>();
melons.add(new Melon(" Cornu honey ", 1, " Thailand "));
melons.add(new Melon(" watermelon ", 2, " sanya "));
melons.add(new Melon(" Yellow river honey ", 3, " lanzhou "));
List<Melon> melonType = Filters.filterMelonByType(melons, " Yellow river honey ");
melonType.forEach(melon->{
System.out.println(" Melon type :"+melon.getType());
});
}

No problem , Show it to the boss , The boss looked at my code and said : If I ask you to add a melon by weight , How are you going to write ? Go back and think about it , This guy doesn't mean to pick on me ?
The second time Select melons by weight
Back in my seat, I thought , Last time I've implemented filtering melons by type , Then I'll give him copy Let's make a change !
As shown below :
/**
* Filter melons by weight
* @param melons
* @param weight
* @return
*/
public static List<Melon> filterMelonByWeight(List<Melon> melons, int weight) {
List<Melon> result = new ArrayList<>();
for (Melon melon: melons) {
if (melon != null && melon.getWeight() == weight) {
result.add(melon);
}
}
return result;
}
public static void main(String[] args) {
ArrayList<Melon> melons = new ArrayList<>();
melons.add(new Melon(" Cornu honey ", 1, " Thailand "));
melons.add(new Melon(" watermelon ", 2, " sanya "));
melons.add(new Melon(" Yellow river honey ", 3, " lanzhou "));
List<Melon> melonType = Filters.filterMelonByType(melons, " Yellow river honey ");
melonType.forEach(melon->{
System.out.println(" Melon type :"+melon.getType());
});
List<Melon> melonWeight = Filters.filterMelonByWeight( melons,3);
melonWeight.forEach(melon->{
System.out.println(" Melon weight :"+melon.getWeight());
});
}

Programmer's favorite way ,CV Get it done , ha-ha . But what I found was that filterByWeight() And filterByType() Very similar , It's just that the filtering conditions are different . I thought. , The boss won't let me write a melon selection by type and weight . Take my code and show it to the boss , Sure enough , What to be afraid of .
third time Select melons by type and weight
In order to fulfill the task of the boss , I mixed the above code together , I quickly wrote the following code
/** * Select melons by type and weight * @param melons * @param type * @param weight * @return */
public static List<Melon> filterMelonByTypeAndWeight(List<Melon> melons, String type, int weight) {
List<Melon> result = new ArrayList<>();
for (Melon melon: melons) {
if (melon != null && type.equalsIgnoreCase(melon.getType()) && melon.getWeight() == weight) {
result.add(melon);
}
}
return result;
}

The boss looked at my code and said , It seems that you still don't understand me . If it wasn't just me today , There are also customers who continue to demand like this .
that Filters There are going to be a lot of similar approaches , That is to say, I wrote a lot of sample code ( The code is redundant but has to be written );
In the eyes of our programmers , This is unacceptable . If you continue to add new filter conditions , The code will become difficult to maintain and error prone . You go to understand lambda expression and Functional interface Knowledge point , Modify your code again . I've made sure , He just can't get along with me
The fourth time Passing behavior as a parameter
After three ups and downs above . I found that in theory Melon Any property of a class can be used as a filter , In this case, our Filter Class will have a lot of boilerplate code , And some of them can be very complicated .
In fact, we can find that , Every time we write a method , They all correspond to a query behavior , The query behavior must correspond to a filter condition . Is there a way? Let's write a way , Pass in the query behavior as a parameter , And then return to our results ?
So give it a name : Behavior parameterization , This is illustrated in the figure below ( The left side shows what we have now ; The right side shows what we want ), Have you found that the template code will be significantly reduced

If we were to Filter conditions As an act , So it's very intuitive to think of each behavior as the implementation of the interface . After analysis, we found that all of these behaviors have one thing in common : Filter conditions and boolean Return of type . Abstract an interface as follows
public interface MelonPredicate {
boolean test(Melon melon);
}
for example , Filter Yellow river honey can write like this : HHMMelonPredicate.
public class HHMMelonPredicate implements MelonPredicate {
@Override
public boolean test(Melon melon) {
return " Yellow river honey ".equalsIgnoreCase(melon.getType());
}
}
And so on , We can also filter a certain weight of melon :
public class WeightMelonPredicate implements MelonPredicate {
@Override
public boolean test(Melon melon) {
return melon.getWeight() > 5000;
}
}
In fact, students who are familiar with design patterns should know that this is : Strategy design pattern .
The main idea is to let the system dynamically select the method to be called at runtime . So we can say MelonPredicate The interface unifies all the algorithms used to filter melons , And each implementation is a strategy , We can also think of it as an act .
at present , We use strategic design patterns , Abstract the query behavior . We also need a way to receive MelonPredicate Parameters . So I defined filterMelons() Method , As shown below :
public static List<Melon> filterMelons(List<Melon> melons, MelonPredicate predicate) {
List<Melon> result = new ArrayList<>();
for (Melon melon: melons) {
if (melon != null && predicate.test(melon)) {
result.add(melon);
}
}
return result;
}
Be accomplished , Test it , Sure enough, it's much easier to use than before , Let the boss see it again
List<Melon> hhm = Filters.filterMelons(melons, new HHMMelonPredicate());
List<Melon> weight = Filters.filterMelons(melons, new WeightMelonPredicate());
The fifth time One time plus 100 Filter conditions
Just when I was smug , The boss poured cold water on him again . He said that you think our platform will buy yellow river honey , If there are dozens of melon varieties before and after , I'll give you a list of 100 Two filter conditions , What would you do ?
In my heart, ten thousand grass mud horses are galloping ! Does the boss mean to have a hard time with me ! Although after the last transformation , My code is flexible enough , But if it suddenly increases 100 Filter conditions , I still need to write 100 A policy class to implement Every filter condition . Then we need to pass the strategy on to filterMelons() Method .
Is there a way not to create these classes ? Smart I soon found that I could use java Anonymous inner class .
As shown below :
List<Melon> europeans = Filters.filterMelons(melons, new MelonPredicate() {
@Override
public boolean test(Melon melon) {
return "europe".equalsIgnoreCase(melon.getOrigin());
}
});
Although a big step forward , But it doesn't seem to help . I still need to write a lot of code to achieve this requirement . The purpose of designing anonymous inner classes , Just for the convenience of Java Programmers pass code as data . occasionally , Anonymous inner classes are more complicated , Now , It suddenly occurred to me that the boss asked me to learn lambda expression , I can use it to simplify
List<Melon> europeansLambda = Filters.filterMelons(
melons, m -> "europe".equalsIgnoreCase(m.getOrigin())
);
Sure enough, it's much more handsome !!!, That's it , Once again, I successfully completed the task . I excitedly took the code to the boss to have a look .
The sixth time Introduce generics
The boss looked at my code and said , Um. , Pretty good ! The brain is finally opening up . Now think about it , Our platform is for agricultural products , That is, there must be more than melons , If you make other fruits , How to modify your code ?
At present, our MelonPredicate Support only Melon class . What's wrong with this guy ? Maybe one day he'll buy vegetables 、 What's wrong with sea cucumbers , We can't create a lot of similar things for him MelonPredicate It's a good interface . At this time, I suddenly remembered what the teacher said Generic , It's time for it to work !
So I defined a new interface Predicate
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Next , We rewrite the filterMelons() Method and rename it to filter() :
public static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> result = new ArrayList<>();
for (T t: list) {
if (t != null && predicate.test(t)) {
result.add(t);
}
}
return result;
}
Now? , We can filter melons like this :
List<Melon> watermelons = Filters.filter(
melons, (Melon m) -> "Watermelon".equalsIgnoreCase(m.getType()));
alike , We can do the same thing with numbers :
List<Integer> numbers = Arrays.asList(1, 13, 15, 2, 67);
List<Integer> smallThan10 = Filters.filter(numbers, (Integer i) -> i < 10);
Let's go back and make a repeat , We found that since using Java 8 Functional interfaces and lambda After expression , The code has changed dramatically .
I don't know if the careful partner has found our above Predicate There's one more on the interface @FunctionalInterface The annotations on , It's the mark Functional interface Of .
thus , We go through an evolution of requirements , I understand lambda And functional interfaces , At the same time, we should deepen our understanding of them . In fact, I am familiar with java8 Our friends all know , In our java.util.function The package contains 40 Multiple such interfaces

Functional interface and lambda expression Formed a strong team . According to the example above , We know that functional interfaces are a high abstraction of our behavior ,lambda Expression we can see an example of a concrete implementation of this behavior .
Predicate<Melon> predicate = (Melon m)-> "Watermelon".equalsIgnoreCase(m.getType());
In short Lambda
lambda Expression consists of three parts , As shown in the figure below :

Here are lambda The description of each part of the expression :
- On the left side of the arrow , Is in
lambdaParameters used in the body of the expression . - On the right side of the arrow , yes
lambdaThe main body . - The arrow is just
lambdaThe separator between the parameter and the body .
this lambda The anonymous class version of is as follows :
List<Melon> europeans = Filters.filterMelons(melons, new Predicate<Melon>() {
@Override
public boolean test(Melon melon) {
return "Watermelon".equalsIgnoreCase(melon.getType());
}
});
Now? , If we look at lambda expression And its An anonymous class edition , It can be described from the following four aspects lambda expression

We can lambda An expression is defined as a concise 、 Transitive anonymous functions , First of all, we need to be clear lambda An expression is essentially a function , Although it doesn't belong to a particular class , But with a parameter list 、 Function main body 、 Return type , It can even throw an exception ; Second, it's anonymous ,lambda The expression has no specific function name ;lambda Expressions can be passed like arguments , So as to simplify the code writing .
Lambda Support Behavior parameterization , In the previous example , We have proved that . Last , please remember ,lambda Expressions can only be used in the context of functional interfaces .
summary
In this paper , We focus on Functional interface The purpose and availability of , We'll look at how to evolve code from the original template code to a flexible implementation based on functional interfaces . Hope to help you understand the functional interface , Thank you. .
边栏推荐
- Observer mode (listener mode) + thread pool to realize asynchronous message sending
- CCS安装编译器的方法
- Thymeleafengine template engine
- FIFO最小深度计算的题目合集
- What should the cross-border e-commerce evaluation team do?
- Functional interface lambda, elegant code development
- Print sparse arrays and restore
- The classification effect of converting video classification data set to picture classification data set on vgg16
- call和apply和bind的区别
- [reading this article is enough!!! Easy to understand] confidence level understanding (95% confidence level and confidence interval)
猜你喜欢

山东大学项目实训之examineListActivity

verilog实现双目摄像头图像数据采集并modelsim仿真,最终matlab进行图像显示

Convert multiple pictures into one NPY file storage

Autojs, read one line, delete one line, and stop scripts other than your own

How to use perforce helix core with CI build server

C语言大战“扫雷”

Warmly celebrate that yeyanxiu, senior consultant of Longzhi, won the title of "atlassian Certified Expert"

The classification effect of converting video classification data set to picture classification data set on vgg16

jenkins-用户权限管理

Super details to teach you how to use Jenkins to realize automatic jar package deployment
随机推荐
Cenos7 builds redis-3.2.9 and integrates jedis
Sqli-libs post injection question 11-17 actual combat
Shuffleerror:error in shuffle in fetcher solution
Make a small game with R language and only basic package
Error reporting injection of SQL injection
C language war "minesweeping"
[reading this article is enough!!! Easy to understand] confidence level understanding (95% confidence level and confidence interval)
MMEditing中超分模型训练与测试
Installing and using sublist3r in Kali
Analyze the capacity expansion mechanism of ArrayList
LeetCodeT526
FPGA interview topic notes (I) - FPGA development process, metastable state and competitive risk, build and hold time, asynchronous FIFO depth, etc
CCF 2013 12-5 I‘m stuck
Sqoop installation tutorial
Matlab实现均值滤波与FPGA进行对比,并采用modelsim波形仿真
Global case | how Capgemini connects global product teams through JIRA software and confluence
View controller and navigation mode
Servlet
FPGA设计——乒乓操作实现与modelsim仿真
FPGA面试题目笔记(四)—— 序列检测器、跨时钟域中的格雷码、乒乓操作、降低静动态损耗、定点化无损误差、恢复时间和移除时间