読書ノート——『Java 8実戦』シリーズの行動パラメータ化
自動回転http://www.wxueyuan.com/blog/articles/2017/10/13/1507857576802.html
最近『Java 8実戦』という本を読んで、いくつかの本の中の重点知識をみんなと共有して、文の中でいくつかの本の中の例を使って、特に声明します.
もし友達がこの本に興味を持っているが、読む時間がないなら、私のブログを見て、この本の重点知識を大体理解することができます.
動作パラメータ化は、その名の通り、コードブロック(動作)をパラメータとして別の方法に渡し、プログラムの他の部分を使用することができます.その最大の利点は、頻繁に交換されるリクエストを処理するために、コードを実行を遅らせることです.
生活の中でよく見られる例を挙げましょう.もし私たちが今学生クラスのStudioを持っているとしたら.
もし私たちが今、180 cm以上の身長の学生を選別する方法を提供する必要があるなら、私たちはどうしますか?
この方法はもちろん皆さんを困らせることはできません.3、2回で完成できます.
もしこの时突然需要が変化したら、要求方法はすべての身長が160 cm以上の学生をスクリーニングして、私たちはまたどのようにしますか?
上のコードをコピーして、180を160に変更しますか?この方法は明らかに望ましくなくて、もし需要がまた変化したら、私たちはもう一度数字を変えることはできません.
このようなコードを書く方法は私たちの抽象化の原則に合わない.
もちろんほとんどの学生は解決策を考えて、身長をパラメータとして方法の中に入れます.
この時、私たちは需要の変化をあまり心配しなくて、私たちに身長以上の学生を得るように要求しても、私たちはそれをパラメータとして方法に伝えることができます.
同様に、平均成績が90点以上の学生を取得する必要がある場合は、前のコードをコピーし、heightパラメータをavgScoreに変更するだけでよい.
このようにするのは簡単そうに見えますが、ほとんどがコードのコピーgetStudentByHeight()とgetStudentByAvgScore()の2つの方法の違いは、意外にも入力されたパラメータだけが異なるだけです.
18歳以上の学生をすべて削除する必要がある場合は?私たちはずっと上のコードをコピーして修正しますか?
では、より良質で抽象的な方法でこの問題を解決することはありますか?
答えは今日のタイトルの動作をパラメータ化したことです
まず、私たちが現在直面している問題を抽象化し、私たちが考えている対象は学生であり、私たちのニーズはいくつかの条件(ここの条件は学生のいくつかの属性)を満たすすべての学生を取得することです.
すべての条件を満たすとtrueを返し,そうでなければfalseを返す方法を抽象化することができる.
このようないくつかの条件が満たされているかどうかに基づいてBoolean値を返す関数を述語(predicate)と呼ぶ.
では、モデリングのためにインタフェースを抽象化します.
私たちが処理しなければならない問題に対して、身長が180 cmより大きい学生と平均成績が90より大きい学生を獲得することに対して、私たちは2つのクラスを確立し、上のインタフェースを実現することができます.
では、ある条件に合致するすべての学生をスクリーニングする必要がある場合、私たちはこのように書くことができます.
呼び出し時に、異なる判断条件に対して異なるpredicateパラメータをパラメータに入れることができます.
他の条件に従って条件を満たす学生を返す必要がある場合は、StudentPredicateインタフェースを実装するために新しいクラスを構築するだけで、既存のコードをコピーして貼る必要がなく、変更に抽象的に対応することができます.
しかし、私たちはまだあまり早く喜ぶことができません.ある学生は、条件を満たすコードがパラメータとして方法に渡されるかどうかを判断するために、StudentPredicateインタフェースを実現した複数のクラスを構築しなければなりません.
これらのメソッドが1、2回しか呼び出されない場合、これらの新しく確立されたクラスは少しうるさいように見えます.
Javaの匿名クラスメカニズムは、1、2回しか使用されていないクラスの構築を避けるのに役立ちます.
簡単に言えば、Javaの匿名クラスでは、クラスを宣言しながらインスタンス化できます.つまり、StudentHeightPredicateとStudentAvgScorePredicateの2つのクラスを構築する必要はありません.
ここを見て学生たちは聞くかもしれませんが、この匿名のメカニズムもJava 8の新しい特性ではありません.どうしてここで苦労して説明しますか.
Java 8で提供されるLambda式は、上記のコードを大きく簡略化することができるからです.
コードがかなり簡素になり、きれいになったのではないでしょうか.Lambda式の詳細については、ブロガーの次のブログを参照してください.
Javaの汎用メカニズムを利用して、私たちのStudentPredicateインタフェースを抽象的な道からもっと遠くまで歩くこともできます.
まず私たちのStudentPredicateを思い出してみましょう
このように書くインタフェースは明らかに抽象的ではなく、汎用的なインタフェースを利用してより抽象的なインタフェースを書くことができます.
StudentFilterは、それに応じて汎用的なFilterメソッドを導入するように変更することもできる.
次のように変更します.
このようなスーパー抽象版のPredicateインタフェースがあれば、ユーザーのニーズは、いくつかの条件を満たすすべての学生を返すか、いくつかの条件を満たすすべての先生を返すことです.
まとめ:挙動パラメータ化は、複数の異なる挙動をパラメータとして受け入れる方法であり、内部でそれらを用いて、異なる挙動を達成する能力 である.動作パラメータ化により、コードは絶えず変化する需要に適応し、将来の作業量 を軽減することができる.伝達コードは、新しい動作をパラメータとして方法に伝達することである.しかし、Java 8の前に実現するのはうるさい.インタフェースに宣言される1回のみのエンティティクラスの多くによる煩わしいコードは、Java 8の前に匿名クラスで を除去することができる.
最近『Java 8実戦』という本を読んで、いくつかの本の中の重点知識をみんなと共有して、文の中でいくつかの本の中の例を使って、特に声明します.
もし友達がこの本に興味を持っているが、読む時間がないなら、私のブログを見て、この本の重点知識を大体理解することができます.
動作パラメータ化は、その名の通り、コードブロック(動作)をパラメータとして別の方法に渡し、プログラムの他の部分を使用することができます.その最大の利点は、頻繁に交換されるリクエストを処理するために、コードを実行を遅らせることです.
生活の中でよく見られる例を挙げましょう.もし私たちが今学生クラスのStudioを持っているとしたら.
class Student{
private String name; //
private int avgScore; //
private int height; //
public Student(String name, int avgScore, int height) {
super();
this.name = name;
this.avgScore = avgScore;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAvgScore() {
return avgScore;
}
public void setAvgScore(int avgScore) {
this.avgScore = avgScore;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
もし私たちが今、180 cm以上の身長の学生を選別する方法を提供する必要があるなら、私たちはどうしますか?
// students ,
public static List getHighStudent(List students){
}
この方法はもちろん皆さんを困らせることはできません.3、2回で完成できます.
public static List getHighStudent(List students){
List highStudents = new ArrayList<>();
for(Student s : students) {
if(s.getHeight()>=180)
highStudents.add(s);
}
return highStudents;
}
もしこの时突然需要が変化したら、要求方法はすべての身長が160 cm以上の学生をスクリーニングして、私たちはまたどのようにしますか?
上のコードをコピーして、180を160に変更しますか?この方法は明らかに望ましくなくて、もし需要がまた変化したら、私たちはもう一度数字を変えることはできません.
このようなコードを書く方法は私たちの抽象化の原則に合わない.
もちろんほとんどの学生は解決策を考えて、身長をパラメータとして方法の中に入れます.
public static List getStudentByHeight(List students, int height){
List highStudents = new ArrayList<>();
for(Student s : students) {
if(s.getHeight()>=height)
highStudents.add(s);
}
return highStudents;
}
この時、私たちは需要の変化をあまり心配しなくて、私たちに身長以上の学生を得るように要求しても、私たちはそれをパラメータとして方法に伝えることができます.
同様に、平均成績が90点以上の学生を取得する必要がある場合は、前のコードをコピーし、heightパラメータをavgScoreに変更するだけでよい.
public static List getStudentByAvgScore(List students, int avgScore){
List highStudents = new ArrayList<>();
for(Student s : students) {
if(s.getHeight()>=avgScore)
highStudents.add(s);
}
return highStudents;
}
このようにするのは簡単そうに見えますが、ほとんどがコードのコピーgetStudentByHeight()とgetStudentByAvgScore()の2つの方法の違いは、意外にも入力されたパラメータだけが異なるだけです.
18歳以上の学生をすべて削除する必要がある場合は?私たちはずっと上のコードをコピーして修正しますか?
では、より良質で抽象的な方法でこの問題を解決することはありますか?
答えは今日のタイトルの動作をパラメータ化したことです
まず、私たちが現在直面している問題を抽象化し、私たちが考えている対象は学生であり、私たちのニーズはいくつかの条件(ここの条件は学生のいくつかの属性)を満たすすべての学生を取得することです.
すべての条件を満たすとtrueを返し,そうでなければfalseを返す方法を抽象化することができる.
このようないくつかの条件が満たされているかどうかに基づいてBoolean値を返す関数を述語(predicate)と呼ぶ.
では、モデリングのためにインタフェースを抽象化します.
interface StudentPredicate{
// , Student
boolean test(Student s);
}
私たちが処理しなければならない問題に対して、身長が180 cmより大きい学生と平均成績が90より大きい学生を獲得することに対して、私たちは2つのクラスを確立し、上のインタフェースを実現することができます.
class StudentHeightPredicate implements StudentPredicate{
@Override
public boolean test(Student s) {
if(s.getHeight()>=180)
return true;
return false;
}
}
class StudentAvgScorePredicate implements StudentPredicate{
@Override
public boolean test(Student s) {
if(s.getAvgScore()>=90)
return true;
return false;
}
}
では、ある条件に合致するすべての学生をスクリーニングする必要がある場合、私たちはこのように書くことができます.
public static List studentFilter(List students, StudentPredicate predicate){
List highStudents = new ArrayList<>();
for(Student s : students) {
// true
if(predicate.test(s))
highStudents.add(s);
}
return highStudents;
}
呼び出し時に、異なる判断条件に対して異なるpredicateパラメータをパラメータに入れることができます.
// 180cm
List filteredStudents = studentFilter(students, new StudentHeightPredicate());
// 90cm
List filteredStudents = studentFilter(students, new StudentAvgScorePredicate());
他の条件に従って条件を満たす学生を返す必要がある場合は、StudentPredicateインタフェースを実装するために新しいクラスを構築するだけで、既存のコードをコピーして貼る必要がなく、変更に抽象的に対応することができます.
しかし、私たちはまだあまり早く喜ぶことができません.ある学生は、条件を満たすコードがパラメータとして方法に渡されるかどうかを判断するために、StudentPredicateインタフェースを実現した複数のクラスを構築しなければなりません.
これらのメソッドが1、2回しか呼び出されない場合、これらの新しく確立されたクラスは少しうるさいように見えます.
Javaの匿名クラスメカニズムは、1、2回しか使用されていないクラスの構築を避けるのに役立ちます.
簡単に言えば、Javaの匿名クラスでは、クラスを宣言しながらインスタンス化できます.つまり、StudentHeightPredicateとStudentAvgScorePredicateの2つのクラスを構築する必要はありません.
// 180cm
List filteredStudents = studentFilter(students, new StudentPredicate() {
@Override
public boolean test(Student s) {
if(s.getHeight()>=180)
return true;
return false;
}
});
// 90cm
List filteredStudents = studentFilter(students, new StudentPredicate() {
@Override
public boolean test(Student s) {
if(s.getAvgScore()>=90)
return true;
return false;
}
});
ここを見て学生たちは聞くかもしれませんが、この匿名のメカニズムもJava 8の新しい特性ではありません.どうしてここで苦労して説明しますか.
Java 8で提供されるLambda式は、上記のコードを大きく簡略化することができるからです.
List filteredStudents2 = studentFilter(students,
Student s -> s.getHeight()>=180
);
コードがかなり簡素になり、きれいになったのではないでしょうか.Lambda式の詳細については、ブロガーの次のブログを参照してください.
Javaの汎用メカニズムを利用して、私たちのStudentPredicateインタフェースを抽象的な道からもっと遠くまで歩くこともできます.
まず私たちのStudentPredicateを思い出してみましょう
interface StudentPredicate{
// , Student
boolean test(Student s);
}
このように書くインタフェースは明らかに抽象的ではなく、汎用的なインタフェースを利用してより抽象的なインタフェースを書くことができます.
interface Predicate{
//
boolean test(T t);
}
StudentFilterは、それに応じて汎用的なFilterメソッドを導入するように変更することもできる.
public static List studentFilter(List students, StudentPredicate predicate){
List highStudents = new ArrayList<>();
for(Student s : students) {
// true
if(predicate.test(s))
highStudents.add(s);
}
return highStudents;
}
次のように変更します.
public static List filter(List list, Predicate predicate){
List result = new ArrayList<>();
for(T t : list) {
// true
if(predicate.test(t))
result.add(t);
}
return result;
}
このようなスーパー抽象版のPredicateインタフェースがあれば、ユーザーのニーズは、いくつかの条件を満たすすべての学生を返すか、いくつかの条件を満たすすべての先生を返すことです.
// 90
List filteredStudents = filter(students, new Predicate(){
@Override
public boolean test(Student s) {
if(s.getAvgScore()>=90)
return true;
return false;
}
});
// 90 Lambda
List filteredStudents = filter(students,
Student s -> s.getAvgScore()>=90
);
// 5000
List filteredTeachers = filter(teachers, new Predicate(){
@Override
public boolean test(Teacher t) {
if(t.getAvgSalary()>=5000)
return true;
return false;
}
});
// 5000 Lambda
List filteredTeachers = filter(teachers,
Teacher t -> t.getAvgSalary()>=5000
);
まとめ: