Strategy(策略) - java 源码中的策略模式

标签(空格分隔): 设计模式


前言

Strategy(策略)设计模式是设计架构时候常用到的设计模式之一。我们开发中常常遇到这样的情况:在实现某一个功能的时候,根据不同的环境和情况实现不同的算法和规则(比如排序功能)。很多人解决的方案就是用if else代替,if(xx)就用a排序方案,if(yy)就用b排序方案,else....。功能的确能实现, 但是以后扩展和维护起来相当不容易。遇到这样的情况(在实现某一个功能的时候,根据不同的环境和情况实现不同的算法和规则),我们可以尝试用策略设计模式来解决这样的问题。

场景1.对一组[1,2,6,4,3,2]进行排序,会怎么写?

  • 程序设计1
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        //数组创建
        Integer a[] = {1,2,6,4,3,2};
        //数组排序
        DataSorter.sort(a);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Integer[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + ",";
        }
        return str;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * 排序工具
 */
public class DataSorter {

    public static void sort(int[] a) {
        for(int i=a.length; i>0; i--) {
            for(int j=0; j<i-1; j++) {
                if(a[j] > a[j+1]) {
                    swap(a, j , j+1);
                }
            }
        }
    }

    private static void swap(int[] a, int x, int y) {
        int temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }

}

排序算法:
![](A14A9750-93DC-488A-9B18-8F8DBC1D5BCF.png)
![](A14A9750-93DC-488A-9B18-8F8DBC1D5BCF.png)

结果:

![](36647C2C-F803-44FD-9380-AC749638C600.png)
![](36647C2C-F803-44FD-9380-AC749638C600.png)


场景2.加入现在我要排序的不是一组 数字了,是要对一组 猫按照体重来排序。

  • 程序设计2
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        //数组创建
        Cat kitty = new Cat("kitty", 3);//kitty,3kg,1year
        Cat tony = new Cat("tony", 6);//tony, 5kg, 2year
        Cat himit = new Cat("himit", 6);//himt, 6kg 3year

        Cat a[] = {kitty, tony, himit};
        //数组排序
        DataSorter.sort(a);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Cat[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + ",";
        }
        return str;
    }
}
public class Cat {
    public Cat(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String name;
    public int weight;

    @Override
    public String toString() {
        return "name-" + name + " weight-" + weight;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * 排序工具
 */
public class DataSorter {
    public static void sort(Cat[] a) {
        for(int i=a.length; i>0; i--) {
            for(int j=0; j<i-1; j++) {
                if(((Cat)a[j]).weight > ((Cat)a[j+1]).weight) {
                    swap(a, j , j+1);
                }
            }
        }
    }

    private static void swap(Cat[] a, Integer x, Integer y) {
        Cat temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
}

结果:

image_1ao5pvh8n1rfh16ov1a9l18v07pr1j.png-27.4kB
image_1ao5pvh8n1rfh16ov1a9l18v07pr1j.png-27.4kB

功能的确实现了。

但出现缺点:

1.要修改更换排序的东西,就必须修改 DataSort 类,违背了设计原则的:《开闭原则》 - 对扩展开放,对修改关闭。

2.也是违背了设计原则中的:《依赖倒置原则》 - 高层模块不应该依赖低层模块,二者都应该依赖其抽象。就是说,类 DataSort依赖了 Cat 类,如果以后要对 Dog 排序,那么就必须修改 DataSort 的类,更改依赖对象把 Cat 改为 Dog。


场景3.现在我需要对猫的名字的长度进行排序,就是 实现结果为:(himit2 ,kitty, tony),要求设计成更下次改回对猫的体重修改的时候,要能改 DataSort修改。

  • 程序设计3
//main 不用动
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        //数组创建
        Cat kitty = new Cat("kitty", 3);//kitty,3kg,1year
        Cat tony = new Cat("tony", 6);//tony, 5kg, 2year
        Cat himit = new Cat("himit", 6);//himt, 6kg 3year

        Cat a[] = {kitty, tony, himit};
        //数组排序
        DataSorter.sort(a);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Cat[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + ",";
        }
        return str;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * 增加一个 Comparable接口
 */
public interface Comparable<T> {
    int compareTo(T o);
}
/**
 * Created by liangjunjie on 16/6/16.
 * 排序工具
 * DataSort 不在依赖 Cat 了,改为依赖接口(抽象)Comparable。
 */
public class DataSorter {
    public static void sort(Comparable[] a) {
        for(int i=a.length; i>0; i--) {
            for(int j=0; j<i-1; j++) {
                Comparable o1 = a[j];
                Comparable o2 = a[j+1];
                if(o1.compareTo(o2) == 1) {
                    swap(a, j , j+1);
                }
            }
        }
    }

    private static void swap(Comparable[] a, int x, int y) {
        Comparable temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * cat 实现接口 Comparable
 */
public class Cat implements Comparable<Cat>{
    public Cat(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String name;
    public int weight;

    @Override
    public String toString() {
        return "name-" + name + " weight-" + weight;
    }

    @Override
    public int compareTo(Cat o) {
        if(this.name.length() > o.name.length()) {
            return 1;
        } else if(this.name.length() < o.name.length()) {
            return -1;
        }  else {
            return 0;
        }
    }
}

结果:


![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)
![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)

改到到这里,你会发现这样的更改,以后更排序方式,不要对 cat 的名字长度排序,而是改回之前对体重进行排序,DataSort 真的不用进行修改,只要对 Cat 类的 compareTo(Cat o) 方法进行一下修改,就可以回到按体重排序。

/**
 * Created by liangjunjie on 16/6/16.
 */
public class Cat implements Comparable<Cat>{
    public Cat(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String name;
    public int weight;

    @Override
    public String toString() {
        return "name-" + name + " weight-" + weight;
    }

    @Override
    public int compareTo(Cat o) {
        //改这里
        if (this.weight > o.weight) {
            return 1;
        } else if (this.weight < o.weight) {
            return -1;
        } else {
            return 0;
        }
    }
}

结果:
![](EB1441FB-8E1E-48E5-9EC2-B19381358C52.png)
![](EB1441FB-8E1E-48E5-9EC2-B19381358C52.png)

但是还不够完善啊,虽然我不用动 DataSort类了,但我还是要动 Cat 类啊,有无方法,DataSort 类和 Cat 类都不用动呢?


场景4.现在我修改对猫的其他属性排序,对我们封装好的东西不用动(不用动 Cat,不用动 DataSort),只需要修改我们的 main 就可以。

  • 程序设计4。给猫添加一个 --- 比较器。
/**
 * Created by liangjunjie on 16/6/16.
 * 比较器
 */
public interface Comparator<T> {
    int compare(T o1, T o2);
}
/**
 * Created by liangjunjie on 16/6/16.
 * 猫的体重比较器
 */
public class CatWeightComparator implements Comparator<Cat> {
    @Override
    public int compare(Cat o1, Cat o2) {
        if(o1.weight > o2.weight) {
            return 1;
        } else if(o1.weight < o2.weight) {
            return -1;
        }  else {
            return 0;
        }
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 */
public class Cat implements Comparable<Cat>{
    public String name;
    public int weight;

    public Cat(String name, int weight, Comparator comparator) {
        this.name = name;
        this.weight = weight;
        this.comparator = comparator;
    }

    
    public Cat(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }


    @Override
    public String toString() {
        return "name-" + name + " weight-" + weight;
    }

    @Override
    public int compareTo(Cat o) {
        //修改这里,根据传入来的策略来比较
        return comparator.compare(this, o);
    }
}

/**
 * Created by liangjunjie on 16/6/16.
 * 排序工具
 */
public class DataSorter {
    public static void sort(Comparable[] a) {
        for(int i=a.length; i>0; i--) {
            for(int j=0; j<i-1; j++) {
                Comparable o1 = a[j];
                Comparable o2 = a[j+1];
                if(o1.compareTo(o2) == 1) {
                    swap(a, j , j+1);
                }
            }
        }
    }

    private static void swap(Comparable[] a, int x, int y) {
        Comparable temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 */
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        //修改这里
        CatNameComparator nameComparator = new CatNameComparator();
        //数组创建
        Cat kitty = new Cat("kitty", 3, nameComparator);//kitty,3kg,1year
        Cat tony = new Cat("tony", 5, nameComparator);//tony, 5kg, 2year
        Cat himit = new Cat("himit2", 6, nameComparator);//himt, 6kg 3year

        Cat a[] = {kitty, tony, himit};
        //数组排序
        DataSorter.sort(a);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Cat[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + "\n";
        }
        return str;
    }
}

这样子,默认就是按照了 weight 进行排序了

结果:

![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)
![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)

貌似上面的真的还有一个地方不靠谱,每次 newcat 的时候也传入一个比较器,所以想了一下,比较器应该是在 DataSort 类的时候传入去的,所以修改成这样

  • 程序设计4,Comparable 接口可以不用了
/**
 * Created by liangjunjie on 16/6/16.
 */
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        CatNameComparator nameComparator = new CatNameComparator();
        //数组创建
        Cat kitty = new Cat("kitty", 3);//kitty,3kg,1year
        Cat tony = new Cat("tony", 5);//tony, 5kg, 2year
        Cat himit = new Cat("himit2", 6);//himt, 6kg 3year

        Cat a[] = {kitty, tony, himit};
        //数组排序
        DataSorter.sort(a, nameComparator);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Cat[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + "\n";
        }
        return str;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * 比较器
 */
public interface Comparator<T> {
    int compare(T o1, T o2);
}
public class Cat{
    public String name;
    public int weight;



    public Cat(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }


    @Override
    public String toString() {
        return "name-" + name + " weight-" + weight;
    }

}
/**
 * Created by liangjunjie on 16/6/16.
 */
public class CatNameComparator implements Comparator<Cat> {
    @Override
    public int compare(Cat o1, Cat o2) {
        if(o1.name.length() > o2.name.length()) {
            return 1;
        } else if(o1.name.length() < o2.name.length()) {
            return -1;
        }  else {
            return 0;
        }
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 * 排序工具, 修改了这个关键类
 */
public class  DataSorter {
    public static <T extends Comparable<? super T>> void sort(T[] a, Comparator<T> comparator) {
        for(int i=a.length; i>0; i--) {
            for(int j=0; j<i-1; j++) {
                T o1 = a[j];
                T o2 = a[j+1];
                if(comparator.compare(o1, o2) >= 1) {
                    swap(a, j , j+1);
                }
            }
        }
    }

    private static <T extends Comparable<? super T>> void swap(T[] a, int x, int y) {
        T temp = a[x];
        a[x] = a[y];
        a[y] = temp;
    }
}
/**
 * Created by liangjunjie on 16/6/16.
 */
public class MainActivity extends Activity{
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv_content);
        //修改这里
        CatNameComparator nameComparator = new CatNameComparator();
        //数组创建
        Cat kitty = new Cat("kitty", 3);//kitty,3kg,1year
        Cat tony = new Cat("tony", 5);//tony, 5kg, 2year
        Cat himit = new Cat("himit2", 6);//himt, 6kg 3year

        Cat a[] = {kitty, tony, himit};
        //数组排序
        DataSorter.sort(a, nameComparator);
        //数组输出到界面
        tv.setText(toStringArray(a));
    }


    /**
     * 把数组转成一段字符串输出到界面
     * @param a
     * @return  一段排好序的字符串
     */
    public String toStringArray(Cat[] a) {
        String str = "";
        for(int i=0; i<a.length; i++) {
            str += a[i].toString() + "\n";
        }
        return str;
    }
}

结果:


![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)
![](E0C9B690-98C0-4D55-8D8F-85AF2D9B1076.png)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,050评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,621评论 18 399
  • 昨天,我对面的同事小s被人事调动去了别的部门,一个比现在更加忙碌、任务更加繁重的部门。小s来了大概一年多,没到两年...
    经典_cj阅读 174评论 4 2
  • 喵喵: 我坐在走廊最边角的地方看着你,你在20米外走廊的另一端,拿着那只完好的左眼看着我,我知道你看不清我,最起码...
    晶晶亮的沙子阅读 297评论 0 3
  • “与恶龙缠斗过久,自身亦成为恶龙。凝视深渊过久,深渊将回以凝视。”——尼采 他打开记事本,看了看上面病人的名字。今...
    清书_阅读 1,329评论 22 51