设计模式:装饰者模式
前言
装饰者(Decorator)模式动态地将责任附加到对象上,若要扩展功能,装饰者模式提供了比继承更加有弹性的替代方案(来自 Head First 设计模式)
UML图
Component:组件接口,每个组件都可以单独使用。也可以被装饰者包装起来使用。
Concrete:具体的组件。扩展自组件接口
Decorator:装饰者接口。
ConcreteDecorator:具体的装饰者。
例子:
需求是旅游的景区需要买门票,但是门票价格不只是原始的价格。针对不同的情况会有不同的价格变化。可能有国庆时候的折扣,也可以有许多类型的优惠券折扣,也可能在基本门票上进行更全面的服务,比如VIP全天包游服务。。。
门票主体
/** * 组件接口 * @author lzp * */ public abstract class Ticket { public String description = "未知门票种类"; public String getDescription() { return description; } //价格计算 public abstract double price(); }
具体的门票(具体的景区门票的种类和基本价格可以从数据库中取,这里仅是演示一下装饰者模式)
public class ScenicTicket extends Ticket{ public ScenicTicket() { description = "景区门票"; } @Override public double price() { return 100; } }
装饰者抽象类
/** * 门票装饰者抽象类 * @author lzp * */ public abstract class TicketDecorator extends Ticket{ public abstract String getDescription(); }
装饰者具体类
国庆优惠价
//国庆优惠 public class NationalDay extends TicketDecorator{ Ticket ticket; public NationalDay(Ticket ticket) { this.ticket = ticket; } @Override public String getDescription() { return ticket.getDescription()+","+"国庆优惠"; } @Override public double price() { return ticket.price()-20; } }
优惠券
//优惠券 public class Coupon extends TicketDecorator{ Ticket ticket; public Coupon(Ticket ticket) { this.ticket = ticket; } @Override public String getDescription() { return ticket.getDescription()+","+"1号优惠劵"; } @Override public double price() { return ticket.price()-10; } }
VIP服务
public class VIPService extends TicketDecorator{ Ticket ticket; public VIPService(Ticket ticket) { this.ticket = ticket; } @Override public String getDescription() { return ticket.getDescription()+","+"VIP全天包邮服务"; } @Override public double price() { return ticket.price()+688; } }
测试代码
public class Main { public static void main(String[] args) { //买一张普通门票 Ticket ticket = new ScenicTicket(); System.out.println(ticket.getDescription()+ticket.price()); //想要VIP服务的门票 Ticket ticket2 = new ScenicTicket(); ticket2 = new VIPService(ticket2); System.out.println(ticket2.getDescription()+ticket2.price()); //买一张VIP服务门票,有国庆优惠和优惠券 Ticket ticket3 = new ScenicTicket(); ticket3 = new VIPService(ticket3); ticket3 = new NationalDay(ticket3); ticket3 = new Coupon(ticket3); System.out.println(ticket3.getDescription()+ticket3.price()); } }
总结:
实际的代码中对于相似的代码,比如各种优惠券之类的,也可以再次进行封装接口。便于调用。
装饰者模式是在不改变原有接口的前提下增强对象的性能。
但是会产生比较多的装饰者类。