Ale*_*sky 58 design-patterns decorator
我正在研究我的设计模式,我在编码中尚未认真使用的一种模式是装饰模式.
我理解这种模式,但我想知道的是现实世界中一些具体的例子,装饰者模式是最佳/最佳/优雅的解决方案.需要装饰器模式的特定情况非常方便.
谢谢.
Pas*_*ent 72
装饰器模式用于向特定对象添加附加功能,而不是一类对象.通过子类化对象很容易为整个对象类添加功能,但是不可能以这种方式扩展单个对象.使用Decorator Pattern,您可以向单个对象添加功能,并保留其他类似对象不受修改.
在Java中,装饰器模式的经典示例是Java I/O Streams实现.
FileReader frdr = new FileReader(filename);
LineNumberReader lrdr = new LineNumberReader(frdr);
Run Code Online (Sandbox Code Playgroud)
上面的代码创建了一个读取器 - lrdr从文件中读取并跟踪行号.第1行创建文件阅读器(frdr),第2行添加行号跟踪.
实际上,我强烈建议您查看Java I/O类的Java源代码.
Cha*_*lts 36
装饰器模式与流使用很多:您可以使用流包装流以获得添加的功能.我已经在.Net框架中看到了这一点 - 据我所知,这发生在其他地方.我最喜欢的是在FileStream周围使用GZipStream来增加压缩.
Kal*_*see 28
我最近在使用以下CommandProcessor接口的Web服务中使用了装饰器模式:
public Command receive(Request request);
public Response execute(Command command);
public void respond(Response response);
Run Code Online (Sandbox Code Playgroud)
基本上,CommandProcessor接收请求并创建适当的命令,执行命令并创建适当的响应,并发送响应.当我想添加时序并记录它时,我创建了一个使用现有CommandProcessor作为其组件的TimerDecorator.TimerDecorator实现了CommandProcessor接口,但只是增加了时序,然后调用了它的目标,即真正的CommandProcessor.像这样的东西:
public class TimerDecorator implements CommandProcessor {
private CommandProcessor target;
private Timer timer;
public TimerDecorator(CommandProcessor processor) {
this.target = processor;
this.timer = new Timer();
}
public Command receive(Request request) {
this.timer.start();
return this.target.receive(request);
}
public Response execute(Command command) {
return this.target.execute(command);
}
public void respond(Response response) {
this.target.response(response);
this.timer.stop();
// log timer
}
}
Run Code Online (Sandbox Code Playgroud)
因此真正的CommandProcessor包含在TimerDecorator中,我可以像处理目标CommandProcessor一样处理TimerDecorator,但现在添加了时序逻辑.
装饰器模式在运行时动态更改对象的功能,而不会影响对象的现有功能.
关键用例:
缺点:
一个现实世界的例子:计算饮料的价格,可能包含多种口味.
abstract class Beverage {
protected String name;
protected int price;
public Beverage(){
}
public Beverage(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
protected void setPrice(int price){
this.price = price;
}
protected int getPrice(){
return price;
}
protected abstract void decorateBeverage();
}
class Tea extends Beverage{
public Tea(String name){
super(name);
setPrice(10);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
class Coffee extends Beverage{
public Coffee(String name){
super(name);
setPrice(15);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
abstract class BeverageDecorator extends Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage){
this.beverage = beverage;
setName(beverage.getName()+"+"+getDecoratedName());
setPrice(beverage.getPrice()+getIncrementPrice());
}
public void decorateBeverage(){
beverage.decorateBeverage();
System.out.println("Cost of:"+getName()+":"+getPrice());
}
public abstract int getIncrementPrice();
public abstract String getDecoratedName();
}
class SugarDecorator extends BeverageDecorator{
public SugarDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateSugar();
}
public void decorateSugar(){
System.out.println("Added Sugar to:"+beverage.getName());
}
public int getIncrementPrice(){
return 5;
}
public String getDecoratedName(){
return "Sugar";
}
}
class LemonDecorator extends BeverageDecorator{
public LemonDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateLemon();
}
public void decorateLemon(){
System.out.println("Added Lemon to:"+beverage.getName());
}
public int getIncrementPrice(){
return 3;
}
public String getDecoratedName(){
return "Lemon";
}
}
public class VendingMachineDecorator {
public static void main(String args[]){
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Cost of:Assam Tea:10
Cost of:Assam Tea+Lemon:13
Added Lemon to:Assam Tea
Cost of:Assam Tea+Lemon+Sugar:18
Added Sugar to:Assam Tea+Lemon
Cost of:Cappuccino:15
Cost of:Cappuccino+Lemon:18
Added Lemon to:Cappuccino
Cost of:Cappuccino+Lemon+Sugar:23
Added Sugar to:Cappuccino+Lemon
Run Code Online (Sandbox Code Playgroud)
该实施例在向饮料中添加许多香料后计算自动售货机中的饮料成本.
在上面的例子中:
茶的成本= 10,柠檬= 3,糖= 5.如果你制作糖+柠檬+茶,它的成本为18.
咖啡的成本= 15,柠檬= 3,糖= 5.如果你制作糖+柠檬+咖啡,它的成本是23
通过对两种饮料(茶和咖啡)使用相同的装饰器,子类的数量已经减少.如果没有Decorator模式,您应该为不同的组合使用不同的子类.
组合将是这样的:
SugarLemonTea
SugarTea
LemonTea
SugarLemonCapaccuino
SugarCapaccuino
LemonCapaccuino
Run Code Online (Sandbox Code Playgroud)
等等
通过对两种饮料使用相同的装饰器,子类的数量已经减少.由于此模式中使用的组合而非继承概念,这是可能的.
相关SE问题:
有用的链接:
dzone的design-patterns-decorator
oodesign文章
装饰器很简单但非常强大.它是实现关注点分离的关键,也是开放封闭原则的重要工具.举一个订购产品的常见例子:
IOrderGateway
{
void PlaceOrder(Order order);
{
Run Code Online (Sandbox Code Playgroud)
主要实施: AmazonAffiliateOrderGateway
可能的装饰者可能是:
IncrementPerformanceCounterOrderGatewayQueueOrderForLaterOnTimeoutOrderGatewayEmailOnExceptionOrderGatewayInterceptTestOrderAndLogOrderGateway看看这里有一个更详细的例子.