当前位置:网站首页>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. .
边栏推荐
- Convert text label of dataset to digital label
- Global case | how an airline with a history of 100 years can expand and transform to promote innovation in the aviation industry
- Why don't we have our own programming language?
- jenkins-不同风格的项目构建
- Moteur de modèle de moteur thymeleaf
- Transfer Learning
- Yonghong Bi product experience (I) data source module
- MySQL implements over partition by (sorting the data in the group after grouping)
- The artistic director and production designer of Disney's Mandalorian revealed the virtual scene production behind it
- All the benefits of ci/cd, but greener
猜你喜欢

C language war "minesweeping"

Which company is better in JIRA organizational structure management?

Topic collection of FIFO minimum depth calculation

Matlab实现均值滤波与FPGA进行对比,并采用modelsim波形仿真

Global case | how Capgemini connects global product teams through JIRA software and confluence

Global case | how an airline with a history of 100 years can expand and transform to promote innovation in the aviation industry

Goodbye 2021 Hello 2022

Shandong University machine learning final 2021

Using Metasploit Trojan horse for remote control

The artistic director and production designer of Disney's Mandalorian revealed the virtual scene production behind it
随机推荐
A collection of problems on improving working frequency and reducing power consumption in FPGA design
CCF 2013 12-5 I‘m stuck
Detailed installation instructions for MySQL
Basic usage of MySQL
jenkins-用户权限管理
Print sparse arrays and restore
Using Metasploit Trojan horse for remote control
Use of constructors
Servlet
Using Internet of things technology to accelerate digital transformation
ERROR 1215 (HY000): Cannot add foreign key constraint
JIRA software annual summary: release of 12 important functions
Metasploitabile2 target learning
Use meshlab to sample the point cloud of CAD model and display it in PCL
Sqoop installation tutorial
Devsecops in Agile Environment
Installing and using sublist3r in Kali
MMEditing中超分模型训练与测试
亚马逊、速卖通、Lazada、虾皮平台在用911+VM的环境可以进行产号、养号、补单等操作吗?
Examinelistactivity of Shandong University project training