设计模式2--装饰者模式(java IO)

装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供比继承更有弹性的替代方案。


设计类(开放-关闭原则):要对扩展开放,对修改关闭。多用组合,少用继承。高内聚低耦合~

具体原因: 当我们设计的类不能满足我们的需求的时候,我们可能设计一个类去继承它,但是这样就会使对象之间高度的耦合。

此时, 我们就可以考虑使用装饰者模式(把对象嵌入我们要扩展功能的类中,调用他的方法,然后跟我们定义的方法一起返回我们需要的类型)。

这个可能跟适配器模式有点相似,但又不同。



UML类图:

我们先来看看装饰者模式的类图,再来详细讲述:
UML类图


1、Component是基类。通常是一个抽象类或者一个接口,定义了属性或者方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类来实现特定的功能,它约束了整个继承树的行为。比如说,如果Component代表人,即使通过装饰也不会使人变成别的动物。
2、ConcreteComponent是Component的子类,实现了相应的方法,它充当了“被装饰者”的角色。
3、Decorator也是Component的子类,它是装饰者共同实现的抽象类(也可以是接口)。比如说,Decorator代表衣服这一类装饰者,那么它的子类应该是T恤、裙子这样的具体的装饰者。
4、ConcreteDecorator是Decorator的子类,是具体的装饰者,由于它同时也是Component的子类,因此它能方便地拓展Component的状态(比如添加新的方法)。

每个装饰者都应该有一个实例变量用以保存某个Component的引用,这也是利用了组合的特性。在持有Component的引用后,由于其自身也是Component的子类,那么,相当于ConcreteDecorator包裹了Component,不但有Component的特性,同时自身也可以有别的特性,也就是所谓的装饰


具体例子:

当我们去咖啡厅的时候。本来你点一杯苦coffe,然后他的价格是10元,你尝了之后发现有点苦,想要加点糖,然后加这个糖的价格是2元;

然后过了一会你的朋友过来了,他叫了一杯拿铁coffee,然后加了点牛奶(假设可以加),这个牛奶的价格是3元。怎么实现?


(一) coffie抽象类

 public abstract class coffee {  
        String coffeeInformation = "普通咖啡";  
        public String getCoffeeInformation(){  
            return coffeeInformation;  
        }  
        public abstract double cost();  
      
    }  


(二)具体被装饰者(coffie的两种具体子类)

 public class coffee1 extends coffee {  
        public coffee1(){  
            coffeeInformation = "coffee1";  
        }  
      
        @Override  
        public double cost() {  
            return 10.0;  
        }  
      
    }  

public class coffee2 extends coffee {  
    public coffee2(){  
        coffeeInformation = "coffee2";  
    }  
  
    @Override  
    public double cost() {  
          
        return 12.0;  
    }  
  
}  

(三)装饰者类(抽象类)

public abstract class  AddThings extends coffee {  
    public abstract String getCoffeeInformation();  
}  

(四)具体装饰者

public class milk extends AddThings{  
    coffee coff;    //创建coffie的引用(组合思想)
    public milk(coffee c) {  
        this.coff = c;  
    }  
  
    @Override  
    public String getCoffeeInformation() {  
        String addThings = coff.getCoffeeInformation()+"添加"+"milk";  
        return addThings;  
    }  
  
    @Override  
    public double cost() {  
      
        return 3.0+ coff.cost();  
    }  
  
}  
public class sugar extends AddThings {  
    coffee coff;  
    public sugar(coffee c) {  
        this.coff = c;  
    }  

    @Override  
    public String getCoffeeInformation() {  
        String addThings = coff.getCoffeeInformation()+"添加"+"sugar";  
        return addThings;  
    }  
  
    @Override  
    public double cost() {  
          
        return 2.0+coff.cost();  
    }  
      
  
}  

(五)

public class cost {  
    public static void main(String[] args) {  
        coffee c1 = new coffee1();  
        coffee c2 = new coffee2();  
        coffee a1 = new sugar(c1);  
        coffee a2 = new milk(c2);    
        System.out.println(a1.getCoffeeInformation()+" "+a1.cost());  
        System.out.println(a2.getCoffeeInformation()+" "+a2.cost());   
          
    }       
}  


装饰者,保存了coffie的引用,实现了cost()方法, 并且在cost()方法内部,不但实现了自己的逻辑,同时也调用了Coffie 引用的cost()方法,即获取了被装饰者的信息,这是装饰者的一个 特点保存引用的目的就是为了获取被装饰者的状态信息,以便将自身的特性加以组合。



韦恩图


特点

(1)装饰者和被装饰者有相同的接口(或有相同的父类)。
(2)装饰者保存了一个被装饰者的引用。
(3)装饰者接受所有客户端的请求,并且这些请求最终都会返回给被装饰者(参见韦恩图)。
(4)在运行时动态地为对象添加属性,不必改变对象的结构。

使用装饰者模式的最大好处就是其拓展性十分良好,通过使用不同的装饰类来使得对象具有多种多样的属性,灵活性比直接继承好。

然而它也有缺点,那就是会出现很多小类,即装饰类,使程序变得复杂。




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值