策略模式(Strategy):
策略模式的定义:
--------定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
--------策略模式使这些算法在客户端调用它们的时候能够互不影响的变化。
策略模式的意义是:
--------策略模式使开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间都是弱连接的关系。
--------弱连接的特性使软件具有更强大的可扩展性,易于维护;更重要的是,它大大的提高了软件的可重用性。
策略模式的组成:
--------抽象的策略角色:策略类,通常由一个结构或者抽象类来实现。
--------具体的策略角色:包装了相关的算法和具体的行为。
--------环境角色:持有一个策略类的引用,最终给客户单调用。
策略模式的实现:
--------策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以互相的替换。
--------策略模式使得算法可以在不影响到客户端的情况下发生变化。使用策略模式可以把行为和环境分开来。
--------环境类负责维持和查询行为类,各种算法则在具体的策略中提供。由于算法和环境独立开来,算法额修改不会影响到客户端和环境。
策略模式的编写的步骤:
1:对策略对象定义一个公共的接口。
2:编写策略类,该类实现了上面的公共的接口。
3:在使用策略的对象类中保存一个对策略对象的引用。
4:在使用策略对象的类中,实现对策略对象的set和get方法,或者使用构造方法完成赋值。
策略模式的缺点:
1:客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
2:造成很多的策略类。
解决的方法是:工厂模式。
简单示例:
import
java.util.ArrayList;
import
java.util.Collections;
import
java.util.Comparator;
import
java.util.List;
public
class
demo {
public
static
void
main(String[] args) {
List<Student> students =
new
ArrayList<Student>();
students.add(
new
Student (
"zhanglei"
,
18
));
students.add(
new
Student (
"daxuesheng"
,
18
));
//按名排序
Util.sort(students,
new
NameCom ());
//按年龄排序
Util.sort(students,
new
AgeCom ());
System.out.println(students.toString());
}
}
class
Student {
private
String name;
private
int
age;
public
Student (String name,
int
age) {
this
.name = name;
this
.age = age;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
@Override
public
String toString() {
return
"name:"
+name+
"age:"
+age;
}
}
class
Util {
public
static
void
sort (List<Student> students,Comparator<Student> c) {
Collections.sort(students, c);
}
}
//按照名字排序的策略
class
NameCom
implements
Comparator<Student> {
@Override
public
int
compare(Student o1, Student o2) {
return
o1.getName().compareTo(o2.getName());
}
}
//按照年龄的排序额策略
class
AgeCom
implements
Comparator<Student> {
@Override
public
int
compare(Student o1, Student o2) {
return
o1.getAge() - o2.getAge();
}
}
|
从策略模式中我们可以学到:
1:封装变化
找出应用中可能需要变化之处,
把它们独立出来,不要和那些不需要变化的代码混在一起。
换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分代码需要被抽出来,和其他稳定的代码有所区分。
另外一种思考方式:把会变化的部分取出并封装起来,以便以后可以轻易的改动或扩充此部分,而不影响不需要变化的其他部分。
2:针对接口编程
针对接口编程真正的意思是"针对超类型(supertype)编程"
这里所谓的"接口"有多个含义,接口是一个"概念",也是一种Java的
interface构造。你可以在不涉及Java interface的情况下,"针对接口编程"
,关键就在多态。利用多态,程序可以在针对超类型编程,执行时会根据
实际状况执行到真正的行为,不会被绑死在超类型的行为上。
"针对超类型编程"这句话,可以更明确地说成"变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。这也意味着,声明类时不用理会以后执行时的真正对象类型!"
3:多用组合,少用继承
"有一个(has-a)"可能比"是一个(is-a)"更好。