1、责任链
应用场景
假设用户向服务器发动数据,由于数据中可能包含敏感词汇或是其他需要实现过滤的信息,因此在数据进入服务器数据库之前需要对信息进行过滤。但是过滤器可能不只是需要一个,而且在以后业务需要增加以后,程序能够很容易的扩展,因此就有了这种责任链设计模式。
第一次设计
现在我们假设用户要向服务器发送一段字符串,但是在字符串中包括敏感词汇和脚本语言,因此在数据录入数据库之前我们要事先进行处理。程序设计如下:
UML图如下
【Main】
public class Main {
public static void main(String[] args) {
// 测试字符串
String testStr = "这里是<script>,里面包含敏感词汇";
StrProcessor strProcessor = new StrProcessor();
strProcessor.setMsg(testStr);
testStr = strProcessor.processor();
System.out.println(testStr);
}
}
【Filter】
public interface Filter {
// 过滤器接口
String doFilter(String str);
}
【HTMLFilterImpl】
public class HTMLFilterImpl implements Filter {
@Override
public String doFilter(String str) {
// 替换html内容
return str.replaceAll("<", "[").replaceAll(">", "]");
}
}
【MsgFilterImpl】
public class MsgFilterImpl implements Filter {
@Override
public String doFilter(String str) {
// 替换敏感词汇问题
return str.replaceAll("敏感", "不敏感");
}
}
【StrProcessor】
public class StrProcessor {
// 接收要处理的字符串
private String msg;
// 存放过滤器的数组
Filter[] filters = { new MsgFilterImpl(), new HTMLFilterImpl() };
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 处理字符串的方法
public String processor() {
String strTemp = this.msg;
// 循环调用过滤器
for (int i = 0; i < filters.length; i++) {
strTemp = filters[i].doFilter(strTemp);
}
return strTemp;
}
}
第二次设计
由于第一次设计只是完成了可任意拔插过滤器的功能,有了简单的可扩展性,现在需要进一步考虑,是否可以任意添加过滤器栈呢?设计:
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
// 测试字符串
String testStr = "这里是<script>,里面包含敏感词汇";
StrProcessor strProcessor = new StrProcessor();
// 加入要过滤的字符串
strProcessor.setMsg(testStr);
//
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new HTMLFilterImpl())//
.addFilter(new MsgFilterImpl());
strProcessor.setFilterChain(filterChain);
testStr = strProcessor.processor();
System.out.println(testStr);
}
}
【Filter】
public interface Filter {
// 过滤器接口
String doFilter(String str);
}
【MsgFilterImpl】
public class MsgFilterImpl implements Filter {
@Override
public String doFilter(String str) {
// 替换敏感词汇问题
return str.replaceAll("敏感", "不敏感");
}
}
【HTMLFilterImpl】
public class HTMLFilterImpl implements Filter {
@Override
public String doFilter(String str) {
// 替换html内容
return str.replaceAll("<", "[").replaceAll(">", "]");
}
}
【StrProcessor】
public class StrProcessor {
// 接收要处理的字符串
private String msg;
// 过滤器链
FilterChain filterChain;
public FilterChain getFilterChain() {
return filterChain;
}
public void setFilterChain(FilterChain filterChain) {
this.filterChain = filterChain;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
// 处理字符串的方法
public String processor() {
return filterChain.doFilter(msg);
}
}
【FilterChain】
public class FilterChain {
// 过滤器集合
List<Filter> filters = new ArrayList<Filter>();
// 增加过滤器
public FilterChain addFilter(Filter filter) {
this.filters.add(filter);
return this;
}
// 处理字符串的方法
public String doFilter(String str) {
// 循环调用过滤器
for (int i = 0; i < filters.size(); i++) {
str = filters.get(i).doFilter(str);
}
return str;
}
}
2、Iterator模式
在List接口的实现类中,由于LinkedList、ArrayList等集合类都实现了Iterator这个接口,那么在其实现类里面都需要实现Iterator接口里面的元素迭代方法,这样的好处在于在一个系统里如果原来用的是LinkedList这个集合类,现在要换成ArrayList这个集合类,直接换掉就可以了,不需要修改其他代码,提高了系统的扩展性。当然在调用的时候是使用接口调用的。
迭代器Iterator就是利用了这种设计方式,见下面类图:
相应代码如下:
【Main】
public class Main {
public static void main(String[] args) {
// 备用交换的list类型
// List<String> list = new ArrayList<String>();
List<String> list = new LinkedList<String>();
list.add("123");
list.add("abc");
list.add("456");
// 不管是什么类型的List,由于都实现了Iterable<T>这个借口,如要要换List类型的时候,就方便多了
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
3、策略模式(Comparable和Comparator接口的实现)
应用场景
对于一个对象数组,我们要完成对这个数组的排序,如果数组里面都是String类型或是int等基本类型的元素的话,完成排序很简单,但是这个数组里面也许会有其他自定义类型的元素,那么就要按照自定义元素的排序规则进行排序,比如定义一个Cat类型的对象,我们可以按照其身高(weigth)或是年龄(age)进行排序。这样我们在写排序方法的时候就只能按照某一个规则进行排序,而不会通用。现在需要实现怎样共通化这个方法。因此就有了策略模式。
第一次设计
我们可以定义一个排序接口Comparable接口,里面有compareTo()方法,这样所有我们自定义的类都去继承这个接口并实现其中的CompareTo方法后,就可以根据本类确定自己确定的排序方法了,由于所有的自定义类都是Comparable的实现类,那么可以用接口调用实现类的方法去共通化排序方法。设计如下:
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
/**
* 目标:有一方法,对于任意的类型的数组(包括对象数组和基本类型数组)实现排序功能。
* */
// Object[] o = { new Cat(25), new Cat(2), new Cat(30), new Cat(12),
// new Cat(56), new Cat(25) };
Object[] o = { new Dog(6, 25), new Dog(6, 2), new Dog(6, 30),
new Dog(6, 12), new Dog(6, 56), new Dog(6, 25) };
SorterMethod.sort(o);
for (int i = 0; i < o.length; i++) {
System.out.println(o[i].toString());
}
}
}
【SorterMethod】
public class SorterMethod {
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void sort(Object[] o) {
// 使用快拍排序
for (int i = o.length; i > 0; i--) {
for (int j = 0; j < i - 1; j++) {
if (((Comparable) o[j]).compareTo(o[j + 1]) == 1) {
swap(o, j, j + 1);
}
}
}
}
private static void swap(Object[] o, int j, int i) {
Object temp = null;
temp = o[j];
o[j] = o[j + 1];
o[j + 1] = temp;
}
}
【Cat】
public class Cat implements Comparable<Cat> {
// 无参构造方法
public Cat() {
}
// 初始化构造方法
public Cat(int age) {
super();
this.age = age;
}
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Cat o) {
if (this.age > o.age)
return 1;
else if (this.age < o.age)
return -1;
else if (this.age == o.age)
return 0;
else
return 1000;
}
@Override
public String toString() {
return "Cat [age=" + age + "]";
}
}
【Dog】
public class Dog implements Comparable<Dog> {
// 无参构造方法
public Dog() {
super();
}
// 初始化构造方法
public Dog(int weigth, int age) {
super();
this.weigth = weigth;
this.age = age;
}
private int weigth;
private int age;
public int getWeigth() {
return weigth;
}
public void setWeigth(int weigth) {
this.weigth = weigth;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Dog o) {
if (this.age > o.age)
return 1;
else if (this.age < o.age)
return -1;
else if (this.age == o.age)
return 0;
else
return 1000;
}
@Override
public String toString() {
return "Dog [weigth=" + weigth + ", age=" + age + "]";
}
}
【Comparable】
public interface Comparable<T> {
public int compareTo(T t);
}
第二次设计
上面的设计其实还不是策略模式,只是体现了多态的好处,现在我们要实现自定义类中排序方法的可拔插性,原因是在原来的自定义类中实现的compareTo()方法中只是把排序方法写死了,而不能随意更换的。因此我们可以定义一个Comparator接口,而在自定义类中把这个接口当做成员变量写在类中,那么我们自己完成的比较器就可以在自定义类中引用了,并实现了比较方法的可插拔性。设计如下:
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
/**
* 目标:有一方法,对于任意的类型的数组(包括对象数组和基本类型数组)实现排序功能。
* */
// Object[] o = { new Cat(25), new Cat(2), new Cat(30), new Cat(12),
// new Cat(56), new Cat(25) };
Object[] o = { new Dog(6, 25), new Dog(6, 2), new Dog(6, 30),
new Dog(6, 12), new Dog(6, 56), new Dog(6, 25) };
SorterMethod.sort(o);
for (int i = 0; i < o.length; i++) {
System.out.println(o[i].toString());
}
}
}
【SorterMethod】
public class SorterMethod {
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void sort(Object[] o) {
// 使用快拍排序
for (int i = o.length; i > 0; i--) {
for (int j = 0; j < i - 1; j++) {
if (((Comparable) o[j]).compareTo(o[j + 1]) == 1) {
swap(o, j, j + 1);
}
}
}
}
private static void swap(Object[] o, int j, int i) {
Object temp = null;
temp = o[j];
o[j] = o[j + 1];
o[j + 1] = temp;
}
}
【Comparable】
public interface Comparable<T> {
public int compareTo(T t);
}
【Comparator】
public interface Comparator<T> {
public int compare(T t1, T t2);
}
【Cat】
public class Cat implements Comparable<Cat> {
// 无参构造方法
public Cat() {
}
// 初始化构造方法
public Cat(int age) {
super();
this.age = age;
}
private int age;
// 可插拔的比较器,如果要换比较器,直接换这个就可以
private Comparator<Cat> comparator = null;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Cat o) {
return comparator.compare(this, o);
}
@Override
public String toString() {
return "Cat [age=" + age + "]";
}
}
【Dog】
public class Dog implements Comparable<Dog> {
// 无参构造方法
public Dog() {
super();
}
// 初始化构造方法
public Dog(int weigth, int age) {
super();
this.weigth = weigth;
this.age = age;
}
private int weigth;
private int age;
// 可插拔的比较器,如果要换比较器,直接换这个就可以
private Comparator<Dog> comparator = null;
public int getWeigth() {
return weigth;
}
public void setWeigth(int weigth) {
this.weigth = weigth;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Dog o) {
return comparator.compare(this, o);
}
@Override
public String toString() {
return "Dog [weigth=" + weigth + ", age=" + age + "]";
}
}
【CatAgeComparator】
public class CatAgeComparator implements Comparator<Cat> {
@Override
public int compare(Cat t1, Cat t2) {
if (t1.getAge() > t2.getAge())
return 1;
else if (t1.getAge() < t2.getAge())
return -1;
else if (t1.getAge() == t2.getAge())
return 0;
else
return 1000;
}
}
【CatWeightComparator】
public class DogWeigthComparator implements Comparator<Dog> {
@Override
public int compare(Dog t1, Dog t2) {
if (t1.getWeigth() > t2.getWeigth())
return 1;
else if (t1.getWeigth() < t2.getWeigth())
return -1;
else if (t1.getWeigth() == t2.getWeigth())
return 0;
else
return 1000;
}
}
【DogAgeComparator】
public class DogAgeComparator implements Comparator<Dog> {
@Override
public int compare(Dog t1, Dog t2) {
if (t1.getAge() > t2.getAge())
return 1;
else if (t1.getAge() < t2.getAge())
return -1;
else if (t1.getAge() == t2.getAge())
return 0;
else
return 1000;
}
}
4、动态代理
应用场景
假设有一个类Car,里面有一个方法move(),在如何不动里面的方法的同时,我们可以计算这个方法的运行时间。这就要用上代理了。在实际应用中,AOP编程的设计模式就是这个,具体比如记录日志,权限管理,事物管理,很多都是用的代理设计模式。
静态代理
静态代理是代理的一种类型,动态代理也是从静态代理中扩展中来的。还是回到上面的假设,我们要计算Car这个类中的move()方法的运行时间,我们可以通过两种方法来实现静态代理,聚合和继承。下面分别来看。设计如下:
聚合
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
// 使用聚合实现静态代理
// Moveable py = new CarProxy(new Car());
// 使用继承实现静态代理
Moveable py = new CarProxy_02();
py.move();
}
}
【Moveable】
public interface Moveable {
public void move();
}
【Car】
public class Car implements Moveable {
@Override
public void move() {
System.out.println("移动");
}
}
【CarProxy】
public class CarProxy_02 extends Car {
@Override
public void move() {
System.out.println("记录日志开始");
super.move();
System.out.println("记录日志结束");
}
}
继承
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
// 使用聚合实现静态代理
// Moveable py = new CarProxy(new Car());
// 使用继承实现静态代理
Moveable py = new CarProxy_02();
py.move();
}
}
【Moveable】
public interface Moveable {
public void move();
}
【Car】
public class Car implements Moveable {
@Override
public void move() {
System.out.println("移动");
}
}
【CarProxy_02】
public class CarProxy_02 extends Car {
@Override
public void move() {
System.out.println("记录日志开始");
super.move();
System.out.println("记录日志结束");
}
}
比较
对于上面两种方法实现静态代理,很明显,使用聚合方式优于使用继承方式。原因在于,如果使用的是继承方法,如果还要在代理上面加别的代理,那就要在原有继承的基础上无限继承下去,再就是如果要交换代理的顺序那就更麻烦了。而使用聚合方式,只要继承于同一个接口,比如Moveable,就可以实现代理的灵活交互使用了,无论是在顺序上还是在其他方面,都有很好的扩展性。
动态代理
对于动态工厂模式,我们现在不去考虑代理类是什么样的,我们只需要把处理方法写出即可。设计如下:
UML图如下
代码如下
【Client】
public class Client {
public static void main(String[] args) throws Exception {
Tank t = new Tank();
// 将要代理的对象交给这个类的处理类
InvocationHandler h = new TimeHandler(t);
Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);
m.move();
}
}
【InvocationHandler】
public interface InvocationHandler {
public void invoke(Object o, Method m);
}
【TimeHandler】
// 处理器
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
System.out.println("记录日志开始");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("记录日志结束");
}
}
【Proxy】
public class Proxy {
/**
* @param infce 要代理的对象
* @param h 代理对象的处理器
* @return
* @throws Exception
*/
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
String methodStr = "";
String rt = "\r\n";
// 得到要代理类的全部方法
Method[] methods = infce.getMethods();
// 将所有得到的方法组装成字符串
for (Method m : methods) {
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" try{" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + //
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
// 拼接类的源代码
String src =
"package dynamicProxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class TankTimeProxy implements " + infce.getName() + "{" + rt +
" public TankTimeProxy(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" dynamicProxy.InvocationHandler h;" + rt +
methodStr +
"}";
// 将类输出成为类文件(.java)
String fileName = "d:/src/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
// 利用jdk的JavaCompiler将其编译成二进制文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,
null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null,
units);
t.call();
fileMgr.close();
// 将编译好的二进制文件用类加载器加载到内存
URL[] urls = new URL[] { new URL("file:/" + "d:/src/") };
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("dynamicProxy.TankTimeProxy");
System.out.println(c);
// 利用反射技术类实例化
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
return m;
}
}
【Moveable】
public interface Moveable {
public void move();
}
【Tank】
public class Tank implements Moveable {
@Override
public void move() {
System.out.println("Tank自己的方法");
}
}
5、工厂系列
应用场景
我们在使用一个类的时候,一般都是先要new出这个类的实例,之后我们再去使用它,但是现在,我们在另一个类(也就是工厂类)中去产生要使用的对象,这个就是工厂模式。Spring的IOC容器就是利用这种方法来产生的对象。
从单例(静态工厂)说起
单例模式也称之为静态工厂,出现的原因是在有些情况下,对于一个类只能有一个实例。因此我们可以这么设计:
第一,使得无参构造方法私有化,这样别人就不能new这个类的实例了。
第二,写出一个这个类本身的静态成员变量,并new一个这个类。
第三,写出一个这个类的返回方法,返回的是这个类中的静态成员变量。
代码如下
【Car】
public class Car {
// 成员变量
private static Car car = new Car();
// 私有化构造方法
private Car() {
}
// 返回方法
public static Car getInstance() {
return car;
}
}
简单工厂
设计如下:
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
VehicleFactory factory = new BroomFactory();
Moveable m = factory.create();
m.run();
}
}
【Moveable】
public interface Moveable {
public void run();
}
【Plane】
public class Plane implements Moveable {
@Override
public void run() {
System.out.println("飞机飞");
}
}
【Broom】
public class Broom implements Moveable {
@Override
public void run() {
System.out.println("一路沙尘暴飞奔而来broom.....");
}
}
【VehicleFactory】
public abstract class VehicleFactory {
public abstract Moveable create();
}
【PlaneFactory】
public class PlaneFactory extends VehicleFactory {
@Override
public Moveable create() {
return new Plane();
}
}
【BroomFactory】
public class BroomFactory extends VehicleFactory {
@Override
public Moveable create() {
return new Broom();
}
}
抽象工厂
设计如下:
UML图如下
代码如下
【Main】
public class Main {
public static void main(String[] args) {
AbstractFactory f = new FoodFactory();
Vehicle v = f.createVehicle();
v.run();
Food a = f.createFood();
a.printName();
}
}
【AbstractFactory】
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Food createFood();
}
【FoodFactory】
public class FoodFactory extends AbstractFactory {
@Override
public Food createFood() {
// TODO Auto-generated method stub
return new Apple();
}
@Override
public Vehicle createVehicle() {
// TODO Auto-generated method stub
return new Car();
}
}
【MagicFactory】
public class MagicFactory extends AbstractFactory {
@Override
public Food createFood() {
// TODO Auto-generated method stub
return new MushRoom();
}
@Override
public Vehicle createVehicle() {
// TODO Auto-generated method stub
return new Broom();
}
}
【Food】
public abstract class Food {
public abstract void printName();
}
【Apple】
public class Apple extends Food {
public void printName() {
System.out.println("apple");
}
}
【MushRoom】
public class MushRoom extends Food {
@Override
public void printName() {
System.out.println("mushroom");
}
}
【Vehicle】
public abstract class Vehicle {
public abstract void run();
}
【Car】
public class Car extends Vehicle {
public void run() {
System.out.println("冒着烟奔跑中car.......");
}
}
【Broom】
public class Broom extends Vehicle{
public void run() {
System.out.println("一路沙尘暴飞奔而来broom.....");
}
}
优劣对比
对于两种工厂模式,其实体类和接口(或抽象父类)都是一样的,区别在于工厂的模式。简单工厂模式对于一个工厂,它产生的是一类接口的实现类,而抽象工厂模式产生的不是一类接口的实现类。
以下设计模式都不常用,也很简单,了解即可。
6、Command模式
直接上代码
【Main】
public class Main {
public static void main(String[] args) {
Food food = new Apple();
food.eat();
}
}
【Food】
public abstract class Food {
public abstract void eat();
}
【Apple】
public class Apple extends Food {
@Override
public void eat() {
System.out.println("apple");
}
}
【Orange】
public class orange extends Food {
@Override
public void eat() {
System.out.println("orange");
}
}
7、State模式
直接上代码
【Main】
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.addState(new AbstractStateImpl_02());
child.cry();
}
}
【Child】
public class Child {
public AbstractState abstractState;
public void addState(AbstractState abstractState) {
this.abstractState = abstractState;
}
public void simle() {
abstractState.simle();
}
public void cry() {
abstractState.cry();
}
}
【AbstractState】
public abstract class AbstractState {
public abstract void simle();
public abstract void cry();
}
【AbstractStateImpl_01】
public class AbstractStateImpl_01 extends AbstractState {
@Override
public void simle() {
System.out.println("simle_01");
}
@Override
public void cry() {
System.out.println("cry_01");
}
}
【AbstractStateImpl_02】
public class AbstractStateImpl_02 extends AbstractState {
@Override
public void simle() {
System.out.println("simle_02");
}
@Override
public void cry() {
System.out.println("cry_02");
}
}
8、Bridge模式
这种模式主要是用来实现类之间的排列组合的。假设现在有三个A类(AClass01,AClass02和AClass03)和两个B类(BClass01和BClass02),现在要实现A类和B类之间的排列组合,这里就用上了这种设计模式,这种设计模式的核心也是聚合。IO流就用来这个设计模式。
代码如下:
【AInterface】
public class AInterface {
}
【AClass01】
public class AClass01 extends AInterface {
}
【AClass02】
public class AClass02 extends AInterface {
}
【AClass03】
public class AClass03 extends AInterface {
}
【BInterface】
public class BInterface {
AInterface a;
}
【BClass01】
public class BClass01 extends BInterface {
public BClass01() {
this.a = new AClass01();
}
}
【BClass02】
public class BClass02 extends BInterface {
public BClass02() {
this.a = new AClass01();
}
}
这样在BClass0x中就会持有AClass0x的引用,这样就可以随意排列组合了。