一、装饰(Decorator)模式的定义
装饰模式是对象的一种结构模式
定义:装饰模式的基本含义是能够动态地为一个对象添加一些额外的行为职责
装饰模式与继承扩展特性的区别
继承:
1、现有对象行为的覆盖:通过重写父类中已有的方法完成
2、添加新的行为职责:通过在子类中添加新的方法完成
继承是为对象类型所引入的是一种“静态”特性扩展,我们必须编写一个子类,并在其中通过语法所支持的“函数覆盖”或“函数添加”的方式扩展其行为特性,这一扩展后的行为特性的获取在“编译期”就被决定,而非“运行期”的扩展模式。Java中一个类只能“单根继承”。
装饰模式
装饰模式正是为了解决“过度依赖使用继承来进行对象的扩展”
目的:对象行为职责扩展
特性:动态(扩展特性在运行期自动获得)
基本实现示意图
原始接口:(ICar) 定义了一个接口方法
默认目标实现类:(Car)对原始接口默认实现方式,在装饰模式中。默认目标实现类被认为是有待扩展的类,其方法move被认为有待扩展的行为方法
装饰实现类:(SuperCar)同样实现了原始接口,即可以是一个抽象类,也可以使一个具体实现类,其内部封装了一个装饰接口对象的实例。
具体实现类:(FlyCar、WaterCar、AICar) 我们可以再move方法中调用原始接口的对象实例car获取默认目标实现类的行为并在其中加入行为扩展实现,也可以自由添加新的行为职责等
源码
/**
* 抽象构建
* @author qjc
*/
public interface ICar {
void move();
}
//ConcreteComponent 具体构件角色(真实对象)
class Car implements ICar{
@Override
public void move() {
System.out.println("陆地跑");
}
}
//Decorator装饰角色
class SuperCar implements ICar{
protected ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
}
@Override
public void move() {
car.move();
}
}
//ConcreteDecorator具体装饰角色
class FlyCar extends SuperCar {
public FlyCar(ICar car) {
super(car);
}
public void fly(){
System.out.println("天上飞!");
}
@Override
public void move() {
super.move();
fly();
}
}
//ConcreteDecorator具体装饰角色
class WaterCar extends SuperCar {
public WaterCar(ICar car) {
super(car);
}
public void swim(){
System.out.println("水上游!");
}
@Override
public void move() {
super.move();
swim();
}
}
//ConcreteDecorator具体装饰角色
class AICar extends SuperCar {
public AICar(ICar car) {
super(car);
}
public void autoMove(){
System.out.println("自动跑!");
}
@Override
public void move() {
super.move();
autoMove();
}
}
测试
public class Client {
public static void main(String[] args) {
Car car = new Car();
car.move();
System.out.println("增加新的功能,飞行");
FlyCar flycar = new FlyCar(car);
flycar.move();
System.out.println("增加新的功能,水里游");
WaterCar waterCar = new WaterCar(car);
waterCar.move();
System.out.println("增加两个新的功能,飞行,水里游");
WaterCar waterCar2 = new WaterCar(new FlyCar(car));
waterCar2.move();
}
}
二、装饰模式的构成要素
1、默认目标实现类封装与具体的装饰实现类或者子类的内部,从而形成对象之间的引用关系
2、具体装饰实现类同样实现了原始接口
由于默认目标实现类Car被原封不动的封装在装饰实现类SupperCar的内部,我们就可以灵活低在装饰实现类FlyCar等中进行非常自由的扩展方式:一方面,我们可以引用到默认目标实现Car的行为方式并加以扩展,看上去就像我们在继承中使用重写特性那样;另一方面,这样的设计完全不影响我们在具体装饰实现类FlyCar中添加新的行为职责。
装饰模式灵活之处在于:
这样的行为职责扩展方式对于客户端的调用而言是完全透明的。
- 适合对默认目标实现(Car)中的多个接口进行排序组合调度
- 适合对默认目标实现(Car)进行选择性扩展
- 适合默认目标实现(Car)未知或者不易扩展的情况
三、装饰模式的应用
用包装处理get方式的乱码
jsp完整继承关系图(双向继承关系):
源码
public class BaseServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String methodName = req.getParameter("cmd");
try{
Method mm = this.getClass().getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
//声明包装类
MyRequest mr = new MyRequest(req);
mm.invoke(this,mr,resp);
}catch(Exception e){
e.printStackTrace();
}
}
}
//包装request
class MyRequest extends HttpServletRequestWrapper{
private HttpServletRequest req;
public MyRequest(HttpServletRequest request) {
super(request);
this.req=request;
}
//修改getparameter方法
@Override
public String getParameter(String name) {
String value = req.getParameter(name);
if(req.getMethod().equals("GET")){
System.err.println("转码");
try{
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
}catch(Exception e){
}
}
return value;
}
}
装饰模式被广发运用在JDK以及J2EE规范设计之中例如
GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig,java.io.Serializable{
private transient ServletConfig config;
//....
}
IO
Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(new File("d:/a.txt"))));
struts2中request、response、session对象的处理
参考
《Struts2技术内幕——深入解析Struts2架构设计与实现原理》
《Java与模式》