java设计模式

来源:互联网 发布:免费域名解析网站软件 编辑:程序博客网 时间:2024/05/21 08:52

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 {@Overridepublic String doFilter(String str) {// 替换html内容return str.replaceAll("<", "[").replaceAll(">", "]");}}

【MsgFilterImpl】

public class MsgFilterImpl implements Filter {@Overridepublic 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 {@Overridepublic String doFilter(String str) {// 替换敏感词汇问题return str.replaceAll("敏感", "不敏感");}}

【HTMLFilterImpl】

public class HTMLFilterImpl implements Filter {@Overridepublic 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;}@Overridepublic 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;elsereturn 1000;}@Overridepublic 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;}@Overridepublic 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;elsereturn 1000;}@Overridepublic 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;}@Overridepublic int compareTo(Cat o) {return comparator.compare(this, o);}@Overridepublic 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;}@Overridepublic int compareTo(Dog o) {return comparator.compare(this, o);}@Overridepublic String toString() {return "Dog [weigth=" + weigth + ", age=" + age + "]";}}

【CatAgeComparator】

public class CatAgeComparator implements Comparator<Cat> {@Overridepublic 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;elsereturn 1000;}}

【CatWeightComparator】

public class DogWeigthComparator implements Comparator<Dog> {@Overridepublic 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;elsereturn 1000;}}

【DogAgeComparator】

public class DogAgeComparator implements Comparator<Dog> {@Overridepublic 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;elsereturn 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 {@Overridepublic void move() {System.out.println("移动");}}

【CarProxy】

public class CarProxy_02 extends Car {@Overridepublic 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 {@Overridepublic void move() {System.out.println("移动");}}

【CarProxy_02】

public class CarProxy_02 extends Car {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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 {@Overridepublic void run() {System.out.println("飞机飞");}}

【Broom】

public class Broom implements Moveable {@Overridepublic void run() {System.out.println("一路沙尘暴飞奔而来broom.....");}}

【VehicleFactory】

public abstract class VehicleFactory {public abstract Moveable create();}

【PlaneFactory】

public class PlaneFactory extends VehicleFactory {@Overridepublic Moveable create() {return new Plane();}}

【BroomFactory】

public class BroomFactory extends VehicleFactory {@Overridepublic 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 {@Overridepublic Food createFood() {// TODO Auto-generated method stubreturn new Apple();}@Overridepublic Vehicle createVehicle() {// TODO Auto-generated method stubreturn new Car();}}

【MagicFactory】

public class MagicFactory extends AbstractFactory {@Overridepublic Food createFood() {// TODO Auto-generated method stubreturn new MushRoom();}@Overridepublic Vehicle createVehicle() {// TODO Auto-generated method stubreturn 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 {@Overridepublic 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 {@Overridepublic void eat() {System.out.println("apple");}}

【Orange】

public class orange extends Food {@Overridepublic 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 {@Overridepublic void simle() {System.out.println("simle_01");}@Overridepublic void cry() {System.out.println("cry_01");}}

【AbstractStateImpl_02】

public class AbstractStateImpl_02 extends AbstractState {@Overridepublic void simle() {System.out.println("simle_02");}@Overridepublic 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的引用,这样就可以随意排列组合了。

9、Mediator和Facade模式

0 0
原创粉丝点击