`
syx278250658
  • 浏览: 3487 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

设计模式---策略模式(Strategy Pattern with java)

 
阅读更多

首发地址:http://www.cnblogs.com/syxchina/archive/2011/10/11/2207017.html

策略模式是一个很简单的模式,也是一个很常用的模式,可谓短小精悍,类库有很多使用策略模式的例子,所以本文以模拟类库为模板,学习策略模式,也熟悉了java类库设计中的精华,加深了我们的OO思想。

1 概念

策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)

2 模拟java类库中Comparable和Comparator接口

本文实现一个简单的排序算法,通过一步步设计,设计Comparable和Comparator接口,理解了策略模式和java类库设计这2个接口的原因和不同用途。

3 最简单的排序例子

public class Test {
	public static void main(String[] args) {
		int[] nums = { 3, 4, 1, 5, 2 };
		DataSortor.sort(nums);
		DataSortor.p(nums);
	}
}
class DataSortor {
	public static void sort(int[] nums) {
		for (int i = 0; i < nums.length; i += 1) {
			for (int j = i + 1; j < nums.length; j += 1) {
				if (nums[i] > nums[j]) {
					nums[i] = nums[i] + nums[j];
					nums[j] = nums[i] - nums[j];
					nums[i] = nums[i] - nums[j];
				}
			}
		}
	}
	public static void p(int[] nums) {
		for (int i : nums) {
			System.out.print(i + " ");
		}
		System.out.println();
	}
}

 

一个最简单使用冒泡的排序一个int数组,优点简单明了,缺点扩展性和代码重用性不强(不考虑算法本身,比如什么样的数据用不用的排序算法),而且支持的类型单一!

4 支持多重类型的排序算法

public class Test {
	public static void main(String[] args) {
		int[] nums = { 3, 4, 1, 5, 2 };
		DataSortor.sort(nums);
		DataSortor.p(nums);
		double[] doubles = { 1.2, 0.3, 2.5, 8.9, 0};
		DataSortor.sort(doubles);
		DataSortor.p(doubles);
		Dog[] dogs = {new Dog(3,3), new Dog(1,1), new Dog(5,5)};
		DataSortor.sort(dogs);
		DataSortor.p(dogs);
	}
}
class DataSortor {
	public static void sort(int[] nums) {
		for (int i = 0; i < nums.length; i += 1) {
			for (int j = i + 1; j < nums.length; j += 1) {
				if (nums[i] > nums[j]) {
					nums[i] = nums[i] + nums[j];
					nums[j] = nums[i] - nums[j];
					nums[i] = nums[i] - nums[j];
				}
			}
		}
	}
	public static void p(Dog[] dogs) {
		for(int i=0; i<dogs.length; i+=1) {
			System.out.print(dogs[i] + " ");
		}
		System.out.println();
	}
	public static void sort(Dog[] dogs) {
		for (int i = 0; i < dogs.length; i += 1) {
			for (int j = i + 1; j < dogs.length; j += 1) {
				if (dogs[i].getHeight()>dogs[j].getHeight()) {
					Dog temp = dogs[i];
					dogs[i] = dogs[j];
					dogs[j] = temp;
				}
			}
		}
	}
	public static void p(double[] doubles) {
		for (double i : doubles) {
			System.out.print(i + " ");
		}
		System.out.println();
	}
	public static void sort(double[] doubles) {
		for (int i = 0; i < doubles.length; i += 1) {
			for (int j = i + 1; j < doubles.length; j += 1) {
				if (doubles[i] > doubles[j]) {
					doubles[i] = doubles[i] + doubles[j];
					doubles[j] = doubles[i] - doubles[j];
					doubles[i] = doubles[i] - doubles[j];
				}
			}
		}
	}
	public static void sort1(int[] nums) {
		for (int i = nums.length - 1; i >= 0; i -= 1) {
			for (int j = 0; j < i; j += 1) {
				if (nums[j] > nums[j+1]) {
					nums[j+1] = nums[j+1] + nums[j];
					nums[j] = nums[j+1] - nums[j];
					nums[j+1] = nums[j+1] - nums[j];
				}
			}
		}
	}
	public static void p(int[] nums) {
		for (int i : nums) {
			System.out.print(i + " ");
		}
		System.out.println();
	}
}
class Dog {
	private int height;
	private int weight;
	public Dog(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Dog(" + height + "," + weight +")";
	}
	
}

输出结果:

1 2 3 4 5 
0.0 0.30000000000000004 1.2000000000000002 2.5 8.9 
Dog(1,1) Dog(3,3) Dog(5,5) 

 

添加了更多基本类型的排序和基本类的比较,但也扩展性和重用性差还是很差。

如果我们继续添加新的类,我们必须重新写比较方法,重新改我们的排序代码,排序算法不能得到重用!所以我们可以添加比较接口!

5 引入Comparable接口

public class Test {
	public static void main(String[] args) {
		Dog[] dogs = { new Dog(3, 3), new Dog(1, 1), new Dog(5, 5) };
		DataSortor.sort(dogs);
		DataSortor.p(dogs);
	}
}
class DataSortor {
	public static void p(Object[] objs) {
		for (int i = 0; i < objs.length; i += 1) {
			System.out.print(objs[i] + " ");
		}
		System.out.println();
	}
	public static void sort(Comparable[] objs) {
		for (int i = 0; i < objs.length; i += 1) {
			for (int j = i + 1; j < objs.length; j += 1) {
				if (objs[i].compareTo(objs[j])>0) {
					Comparable temp = objs[i];
					objs[i] = objs[j];
					objs[j] = temp;
				}
			}
		}
	}
}
interface Comparable {
	int compareTo(Object obj);
}
class Dog implements Comparable {
	private int height;
	private int weight;
	public Dog(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	@Override
	public String toString() {
		return "Dog(" + height + "," + weight + ")";
	}
	@Override
	public int compareTo(Object obj) {
		if (obj instanceof Dog) {
			Dog d = (Dog) obj;
			if (height > d.getHeight())
				return 1;
			else
				return -1;
		}
		return 0;
	}
}

实现了Comparable接口的类,都可以使用排序算法,而不需要更改算法代码!提高的可用性,据有很大的扩展性。

但实现Comparable接口实现比较方法不能解决使用其他比较策略比较大小,比如上面使用cat的height作为比较依据,可能以后使用cat的weight作为比较依据。所以我们提出了策略模式,引入了Comparator接口,可以让cat选择比较策略,来实现不同的比较方法。

6 引入Comparator接口

public class Test {
	public static void main(String[] args) {
		Dog[] dogs = { new Dog(3, 3), new Dog(1, 1), new Dog(5, 5) };
		DataSortor.sort(dogs);
		DataSortor.p(dogs);
	}
}
class DataSortor {
	public static void p(Object[] objs) {
		for (int i = 0; i < objs.length; i += 1) {
			System.out.print(objs[i] + " ");
		}
		System.out.println();
	}

	public static void sort(Comparable[] objs) {
		for (int i = 0; i < objs.length; i += 1) {
			for (int j = i + 1; j < objs.length; j += 1) {
				if (objs[i].compareTo(objs[j]) > 0) {
					Comparable temp = objs[i];
					objs[i] = objs[j];
					objs[j] = temp;
				}
			}
		}
	}
}
interface Comparable {
	int compareTo(Object obj);
}
interface Comparator {
	int compare(Object o1, Object o2);
}
class DogHeightComparator implements Comparator {
	@Override
	public int compare(Object o1, Object o2) {
		if (!(o1 instanceof Dog))
			return 0;
		if (!(o2 instanceof Dog))
			return 0;
		Dog dog1 = (Dog) o1;
		Dog dog2 = (Dog) o2;
		if (dog1.getHeight() > dog2.getHeight())
			return 1;
		else if (dog1.getHeight() < dog2.getHeight())
			return -1;
		return 0;
	}

}
class Dog implements Comparable {
	private int height;
	private int weight;
	private Comparator comparator = new DogHeightComparator();
	@Override
	public String toString() {
		return "Dog(" + height + "," + weight + ")";
	}
	@Override
	public int compareTo(Object obj) {
		return comparator.compare(this, obj);
	}
	public Dog(int height, int weight) {
		super();
		this.height = height;
		this.weight = weight;
	}
	
	public Comparator getComparator() {
		return comparator;
	}

	public void setComparator(Comparator comparator) {
		this.comparator = comparator;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}
}

这样可以设计不同的Comparator来实现不同的比较方式,大大的提高了程序的扩展性,但值得说的类也要实现Comparable接口,只是在Comparable接口的实现方法中使用我们自己设置的排序策略,当然我们可以指定默认的排序算法,如上,这样如果有特殊需求时,在设置相应的排序算法,极大的提高了系统的灵活性。

现在,应该对策略模式有点较深的认识了吧,知道了为什么java类库中为什么有了Comparable还有Comparator接口了吧。

7 策略模式优缺点

优点:

1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。

2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

8 简单工厂模式和策略模式区别(摘录,出处

这两种模式的作用就是拥抱变化,减少耦合。在变化来临时争取做最小的改动来适应变化。这就要求我们把些“善变”的功能从客户端分离出来,形成一个个的功能类,然后根据多态特性,使得功能类变化的同时,客户端代码不发生变化。

简单工厂模式

简单工厂模式:有一个父类需要做一个运算(其中包含了不同种类的几种运算),将父类涉及此运算的方法都设成虚方法,然后父类派生一些子类,使得每一种不同的运算都对应一个子类。另外有一个工厂类,这个类一般只有一个方法(工厂的生成方法),这个方法的返回值是一个超类,在方法的内部,根据传入参数的不同,分别构造各个不同的子类的对象,并返回。客户端并不认识子类,客户端只认识超类和工厂类。每次客户端需要一中运算时,就把相应的参数传给工厂类,让工厂类构造出相应的子类,然后在客户端用父类接收(这里有一个多态的运用)。客户端很顺理成章地用父类的计算方法(其实这是一个虚方法,并且已经被子类特化过了,其实是调用子类的方法)计算出来结果。如果要增加功能时,你只要再从父类中派生相应功能的子类,然后修改下工厂类就OK了,对于客户端是透明的。

策略模式

策略模式:策略模式更直接了一点,没有用工厂类,而是直接把工厂类的生成方法的代码写到了客户端。客户端自己构造出了具有不同功能的子类(而且是用父类接收的,多态),省掉了工厂类。策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。这里的算法家族和简单工厂模式里的父类是同一个概念。当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为,将这些行为封装在一个个独立的策略子类中,可以在客户端中消除条件语句。

简单工厂模式+策略模式:为了将工厂方法的代码从客户端移出来,我们把这些代码搬到了父类的构造函数中,让父类在构造的时候,根据参数,自己实现工厂类的作用。这样做的好处就是,在客户端不用再认识工厂类了,客户端只要知道父类一个就OK,进一步隔离了变化,降低了耦合。

在基本的策略模式中,选择所用具体实现的职责由客户端对象成端,并转给客户端。这本身并没有减除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由父类承担,这就最大化地减轻了客户端的职责。

9 总结

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

10参考资料

维基百科:策略模式

博客园:策略模式:ColinSong

简单工厂模式和策略模式区别:崔玉松

 

作者:syxChina
出处:http://syxchina.cnblogs.com http://hi.baidu.com/syxcs123 
本文版权归作者、博客园和百度空间共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则作者会诅咒你的。

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    (更新至2022年)城镇男性就业人员调查周平均工作时间.xls

    数据来源:中国人口与就业统计NJ-2023版

    各地区技工院校综合情况(2022年).xls

    数据来源:中国劳动统计NJ-2023版

    基于matlab实现样本熵算法,可用于提取生理信号的特征参数

    基于matlab实现样本熵算法,可用于提取生理信号的特征参数,运算速度较快,m=1或2;r=0.1_std(data)~0.25_std(data)最佳。.rar

    蜂网-SCM车销访销业务.pptx

    蜂网_SCM车销访销业务.pptx

    数据更新至2020年国民经济主要指标一览表.xls

    数据来源:中国电力统计NJ-2021版

    图书借阅管理系统设计与实现及论大学生写作能力.docx

    图书借阅管理系统设计与实现及论大学生写作能力.docx

    node-v10.19.0-linux-armv6l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    商品零售价格分类指数(2022年)(上年=100).xls

    数据来源:中国劳动统计NJ-2023版

    数据更新至2020年电网建设 本年开工规模.xls

    数据来源:中国电力统计NJ-2021版

    基于数据服务的信息需求管理系统设计与实现.docx

    基于数据服务的信息需求管理系统设计与实现.docx

    基于matlab实现的多个无人机的群飞行仿真 多个无人机的群飞行仿真.rar

    基于matlab实现的多个无人机的群飞行仿真 多个无人机的群飞行仿真.rar

    #-001-mysql-快递管理系统ssm(毕设和论文)

    随着物流行业信息化的深入使得物流过程中货物的状态和变化透明化,现代信息化的接入使得物流成本和费用的更容易被掌握,从而增强了信息的准确性。与此同时动态信息能够被及时掌握,根据实际情况做出快速而有效的反应,实现物流运作的动态决策。信息的及时、全面的获取与加工,供需双方可以充分的信息共享与沟通,使得物流服务更准确、从而提高客户的满意度;同时顾客可以有更多自我服务功能,可以随意定义自己的定制的物流服务;另外在提供物流服务的同时,可以为顾客提供信息、资金等双赢的增值服务。 该系统用spring mvc和MySQL实现了快递管理系统。快递管理系统有着很好的应用前景,随着计算机技术和网络技术的发展,它的功能将会得到不断的发展和完善。本系统可以根据实际应用的具体情况,适当加以修改,以便更好应用。本系统操作简单,灵活性好,系统安全性高,运行稳定。本文详细介绍了快递管理系统开发和设计的全过程。

    各地区分行业其他单位就业人员和工资总额(2022年).xls

    数据来源:中国劳动统计NJ-2023版

    node-v11.14.0-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于VB实现的医疗纠纷检索系统设计(源代码+系统).zip

    【作品名称】:基于VB实现的医疗纠纷检索系统设计(源代码+系统) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。

    数据更新至2020年分布式太阳能发电情况.xls

    数据来源:中国电力统计NJ-2021版

    node-v11.3.0-linux-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    农村居民分地区人均可支配收入来源(2022年).xls

    数据来源:中国劳动统计NJ-2023版

    tensorflow-rocm-2.13.1.600-cp39-cp39-manylinux2014-x86-64.whl

    cnn

    node-v10.14.1-linux-arm64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics