剑客
关注科技互联网

设计模式之装饰者模式:婚纱照收费的简单实现

装饰者模式

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

装饰者模式特点

  1. 装饰者和被装饰对象有相同的超类型。
  2. 你可以用一个或者多个装饰者包装一个对象。 
  3. 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
  4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  5. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。

装饰者模式类图

设计模式之装饰者模式:婚纱照收费的简单实现

从上图可以看出,装饰者和被装饰者拥有共同的父类Componet,为了方便后面的扩展,我们加了一个装饰者父类Decorator,让Decorator去继承Componet,然后让众多装饰者去继承Decorator。

应用场景(婚纱照收费)

生活中符合装饰者模式的应用场景其实还挺多,就拿前阵子去拍婚纱照的经历来说吧,婚纱工作人员一般先会跟你整体说,拍什么样的场景,多少套衣服,怎么去收费,然后在不改变原有收费的前提下,会跟你说精修入册数量,每加一张,就加收多少钱。现在我们来把这个分级收费模式抽象一下,假如说,我们拍摄一张照片是40块钱,精修一张40块,入册10块。安插在装饰者模式中,照片本身就成了我们说的被装饰者(ConcreteComponet),而精修和入册则符合我们对装饰者的定义,分别为DecoratorA,DecoratorB。接下来我们来实现一下这个应用场景的类图结构。

照片本身 照片入册 照片精修
费用 40 10 40

场景(婚纱照收费)类图

设计模式之装饰者模式:婚纱照收费的简单实现

Format为装饰者父类与WeddingPhoto(被装饰者)共同继承了Photo。IsPhotoAlbum(入册)与PhotoWithPs(精修)为装饰者,共同修饰WeddingPhoto。他们都拥有共同的行为cost(),用于计算出价格,description属性主要用于记录信息,方便查看实现结果,可要可不要。

代码实现

共同抽象父类

package decorate.base;
/**
 * 照片父类
 * @author vision
 */
public abstract class Photo {
	private String description="";
	
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	/**
	 * 价格
	 * @param price
	 * @return
	 */
	public abstract Double cost();

}

装饰者抽象父类

package decorate.format;

import decorate.base.Photo;
/**
 * Format(照片规格)装饰者,扩展自Photo父类
 * @author vision
 */
public abstract class Format extends Photo{
	/**
	 * 描述
	 * @param description
	 * @return
	 */
	public abstract String getDescription();
}

被装饰者(婚纱照)

package decorate;

import decorate.base.Photo;
/**
 * 被装饰者:婚纱照
 * @author vision
 */
public class WeddingPhoto extends Photo{
	
	public WeddingPhoto() {
		setDescription(getDescription()+"WeddingPhoto(婚纱照)");
	}
	@Override
	public Double cost() {
		return 40.0;
	}

}

装饰者(入册)

package decorate.format;

import decorate.base.Photo;
/**
 * 装饰者:照片是否入册
 * @author vision
 */
public class IsPhotoAlbum extends Format{
	private Photo photo;
	public IsPhotoAlbum(Photo photo) {
		this.photo=photo;
	}
	@Override
	public String getDescription() {
		return photo.getDescription()+"+IsPhotoAlbum(入册)";
	}

	@Override
	public Double cost() {
		// TODO Auto-generated method stub
		return 10.0+photo.cost();
	}

}

装饰者(精修)

package decorate.format;

import decorate.base.Photo;
/**
 * 装饰者:照片精修
 * @author vision
 */
public class PhotoWithPs extends Format{
	private Photo photo;
	
	public PhotoWithPs(Photo photo){
		this.photo=photo;
	}
	
	@Override
	public String getDescription() {
		return photo.getDescription()+"+PhotoWithPs(精修)";
	}
	/**
	 * 照片精修,每张多加40块
	 */
	@Override
	public Double cost() {
		return 40.0+photo.cost();
	}

}

测试类

package decorate;

import decorate.base.Photo;
import decorate.format.IsPhotoAlbum;
import decorate.format.PhotoWithPs;

public class TestClass {
	public static void main(String[] args) {
		Photo weddingPhoto=new WeddingPhoto();
		//精修
		PhotoWithPs photoWithPs=new PhotoWithPs(weddingPhoto);
		System.out.println("最终选择的照片为:"+photoWithPs.getDescription());
		System.out.println("最终单价为:"+photoWithPs.cost());
		//入册
		IsPhotoAlbum isPhotoAlbum=new IsPhotoAlbum(photoWithPs);
		System.out.println("最终选择的照片为:"+isPhotoAlbum.getDescription());
		System.out.println("最终单价为:"+isPhotoAlbum.cost());
	}
}

输出结果

设计模式之装饰者模式:婚纱照收费的简单实现

备注

参考资料:《Head First 设计模式》

相关文章: 《设计模式——观察者模式:天气推送的两种实现》

《设计模式——策略模式:会员价格体系的简单实现

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址