文章目錄
我們很容易理解整型的 i>j 這樣的比較方式,但當(dāng)我們對多個對象進(jìn)行排序時,如何比較兩個對象的“大小”呢?這樣的比較 stu1 > stu2 顯然是不可能通過編譯的。
為了解決如何比較兩個對象大小的問題,JDK提供了兩個接口 java.lang.Comparable 和 java.util.Comparator 。
Comparable
Comparable接口
所有可以 “排序” 的類都實(shí)現(xiàn)了java.lang.Comparable接口,Comparable接口中只有一個方法。Comparable接口中只有一個方法:實(shí)現(xiàn)了 Comparable 接口的類通過實(shí)現(xiàn) comparaTo 方法從而確定該類對象的排序方式。
public int compareTo(T o);
返回 0 表示 this == obj
返回整數(shù)表示 this > obj
返回負(fù)數(shù)表示 this < obj
調(diào)用此方法的對象,也就是this和o進(jìn)行比較,若返回值大于0則this大于o,返回值等于0則是this等于o,返回值小于0則是this<o,而這個Comparable是直接在我們的自定義類User上實(shí)現(xiàn),因?yàn)閠his是需要一個明確的比較對象的,也就是一般情況下我們會在定義User類的時候有排序的需求,就要實(shí)現(xiàn)此接口。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class UserComparable implements Comparable<UserComparable> {
private String name;
private int age;
public UserComparable(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "UserComparable{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(UserComparable o) {
//由于字符串無法直接比較大小,所以調(diào)用String類的compareTo
if (this.name.compareTo(o.name)==0){
if (this.age == o.age){
return 0;
}else if (this.age >o.age){
return 1;
}else {
return -1;
}
}else if (this.name.compareTo(o.name)>0){
return 1;
}else {
return -1;
}
}
public static void main(String[] args) {
List<UserComparable> list = new ArrayList<UserComparable>();
list.add(new UserComparable("gol",21));
list.add(new UserComparable("gol",19));
list.add(new UserComparable("xiao",21));
list.add(new UserComparable("long",21));
System.out.println("排序前:"+list);
//排序規(guī)則:先按name排序,若name相等則再比較age
Collections.sort(list);
System.out.println("排序后:"+list);
}
}
Comparator:
Comparator接口中方法很多,但是我們只需要實(shí)現(xiàn)一個,也是最重要的一個compare,也許有的人會好奇為什么接口中的方法可以不用實(shí)現(xiàn),因?yàn)檫@是JDK8以后的新特性,在接口中用default修飾的方法可以有方法體,在實(shí)現(xiàn)接口的時候可以不用重寫,可以類比抽象類。
int compare(T o1, T o2);
compare比較的o1和o2,返回值大于0則o1大于o2,依次類推,對于compare來說this是誰不重要,所比較的兩個對象都已經(jīng)傳入到方法中,所以Comparator就是個外部比較器,在我們設(shè)計User初時,并不需要它有比較功能,在后期擴(kuò)展業(yè)務(wù)是,Comparator的存在可以使我們在不修改源代碼的情況下來完成需求,只需要新定義一個比較器來實(shí)現(xiàn)Comparator,重寫compare方法并將User對象傳進(jìn)去。
public class emp {
public int age;
public String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public emp(int age, String name) {
super();
this.age = age;
this.name = name;
}
public emp() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "emp [age=" + age + ", name=" + name + "]";
}
}
import org.junit.Test;
import junit.framework.TestCase;
public class TestCompare extends TestCase {
@Test
public void test2(){
List<emp> list=new ArrayList<emp>();
emp test1=new emp(69,"李四");
emp test2=new emp(29,"王五");
emp test3=new emp(28,"趙六");
emp test4=new emp(20,"錢三");
list.add(test4);
list.add(test3);
list.add(test2);
list.add(test1);
Collections.sort(list,new Comparator<emp>(){
@Override
public int compare(emp o1, emp o2) {
if(o1.age==o2.age&&o1.name==o2.name){
return 0;
}else if(o1.age>o2.age){
return 1;
}else{
return 0;
}
}
});
for(Object s:list){
System.out.println(s);
}
}
}
結(jié)論:
1、Comparator 使用比較靈活,不需要修改實(shí)體類源碼,但是需要實(shí)現(xiàn)一個比較器。
2、Comparable 使用簡單,但是對代碼有侵入性,需要修改實(shí)體類源碼。
3、java中大部分我們常用的數(shù)據(jù)類型的類都實(shí)現(xiàn)了Comparable接口,而僅僅只有一個抽象類RuleBasedCollator實(shí)現(xiàn)了Comparator接口 ,還是我們不常用的類,
這并不是說要用Comparab而不要使用Comparator,在設(shè)計初時有需求就選擇Comparable,若后期需要擴(kuò)展或增加排序需求是,再增加一個比較器Comparator,畢竟能寫Collections.sort(arg1),沒人樂意寫Collections.sort(arg1,arg2)。
策略模式
在策略模式(Strategy Pattern)中,一個類的行為或其算法可以在運(yùn)行時更改。這種類型的設(shè)計模式屬于行為型模式。
在策略模式中,我們創(chuàng)建表示各種策略的對象和一個行為隨著策略對象改變而改變的 context 對象。策略對象改變 context 對象的執(zhí)行算法。
介紹
意圖:定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。
主要解決:在有多種算法相似的情況下,使用 if...else 所帶來的復(fù)雜和難以維護(hù)。
何時使用:一個系統(tǒng)有許多許多類,而區(qū)分它們的只是他們直接的行為。
如何解決:將這些算法封裝成一個一個的類,任意地替換。
關(guān)鍵代碼:實(shí)現(xiàn)同一個接口。
應(yīng)用實(shí)例: 1、諸葛亮的錦囊妙計,每一個錦囊就是一個策略。 2、旅行的出游方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個策略。 3、JAVA AWT 中的 LayoutManager。
優(yōu)點(diǎn): 1、算法可以自由切換。 2、避免使用多重條件判斷。 3、擴(kuò)展性良好。
缺點(diǎn): 1、策略類會增多。 2、所有策略類都需要對外暴露。
使用場景: 1、如果在一個系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動態(tài)地讓一個對象在許多行為中選擇一種行為。 2、一個系統(tǒng)需要動態(tài)地在幾種算法中選擇一種。 3、如果一個對象有很多的行為,如果不用恰當(dāng)?shù)哪J?,這些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)。
注意事項(xiàng):如果一個系統(tǒng)的策略多于四個,就需要考慮使用混合模式,解決策略類膨脹的問題。
實(shí)現(xiàn)
我們將創(chuàng)建一個定義活動的 Strategy 接口和實(shí)現(xiàn)了 Strategy 接口的實(shí)體策略類。Context 是一個使用了某種策略的類。
StrategyPatternDemo,我們的演示類使用 Context 和策略對象來演示 Context 在它所配置或使用的策略改變時的行為變化。

步驟 1
創(chuàng)建一個接口。

步驟 2
創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類。



步驟 3
創(chuàng)建 Context 類。

步驟 4
使用 Context 來查看當(dāng)它改變策略 Strategy 時的行為變化。

步驟 5
執(zhí)行程序,輸出結(jié)果:
