美文网首页
装饰者模式

装饰者模式

作者: 朕要回幼儿园 | 来源:发表于2019-02-19 11:58 被阅读0次

1、现有咖啡馆订单系统项目(示例项目)

咖啡种类:Espresso、ShortBlack、LongBlack、Decaf

调料:Milk、Soy、Chocolate

实现客户点单时,点个Decaf+milk+Soy可以立刻知道它的价格和描述,点个Decaf需要知道它的价格和描述

2、以传统的面向对象的原则设计这个项目。

1)定义一个超类

public abstract class Drink{

    protected Stringdescription ="";

    protected float price;

    protected abstract StringgetDescription();

    protected abstract float cost();

}

2)把所有的能单点的饮料都封装好描述和价格,继承Drink

public class Coffee extends Drink {

    public Coffee(){

        this.price =5.0f;

        this.description ="coffee"+"-"+this.price;

    }

    @Override

    protected String getDescription() {

        return this.description;

    }

    @Override

    protected float cost() {

        return this.price;

    }

}

3)如果要多点的则把单点的饮料作为引用放在此类中

public class CoffeeAndMilkextends Drink {

    private Coffeecoffee;

    private Milkmilk;

    public CoffeeAndMilk(Coffee coffee,Milk milk){

        this.coffee = coffee;

        this.milk = milk;

    }

@Override

    protected StringgetDescription() {

        return this.coffee.getDescription()+"&&"+this.milk.getDescription();

    }

@Override

    protected float cost() {

        return this.milk.cost()+this.coffee.cost();

    }

}

4)运行结果

Coffee coffee =new Coffee();

System.out.println("描述:"+coffee.getDescription());

System.out.println("价格:"+coffee.cost());

System.out.println("********************************************************");

Milk milk =new Milk();

System.out.println("描述:"+milk.getDescription());

System.out.println("价格:"+milk.cost());

System.out.println("********************************************************");

CoffeeAndMilk coffeeAndMilk =new CoffeeAndMilk(coffee,milk);

System.out.println("描述:"+coffeeAndMilk.getDescription());

System.out.println("价格:"+coffeeAndMilk.cost());

结果:

描述:coffee-5.0

价格:5.0

********************************************************

描述:milk-3.0

价格:3.0

********************************************************

描述:coffee-5.0&&milk-3.0

价格:8.0

问题:这样设计的话,增删饮料种类就很有问题,添加新的混合饮料的话非常麻烦,需要改动两个地方,新增单品饮料,新增复合饮料。搭配品种更不方便,假如我现在coffee不和牛奶混合,coffee和啤酒混合,就必须新建个复合饮料coffeeAndBeer类,扩展性不好,维护起来麻烦。

3、接下来我采用装饰者模式的方式改造代码

   1)封装一个抽象接口,在装饰者模式中的角色是抽象组件角色。

    public abstract class Drink{

        public Stringdescription ="";

        private float price =0f;

        public void setDescription(String description) {

            this.description = description;

        }

        public void setPrice(float price) {

            this.price = price;

        }

        public StringgetDescription() {

            return description+"-"+this.getPrice();

        }

       public float getPrice() {

            return price;

        }

        public abstract float cost();

}

    2)为这个抽象接口提供具体实现类,这里我还封装了一个中间层,这个抽象接口的具体实现应该是这个中间层的具体实现

Coffee中间层代码:

    public class Coffeeextends Drink {

        @Override

        public float cost() {

            return super.getPrice();

        }

    }

具体实现Decaf代码:

public class Decafextends Coffee {

    public Decaf(){

        super.setDescription("Decaf");

        super.setPrice(3.0f);

    }

}

3)创建抽象装饰接口Decorator,包含抽象接口Drink的引用

public class Decorator extends Drink {

private Drinkobj;

    public Decorator(Drink obj){

        this.obj = obj;

    }

    @Override

    public float cost() {

        return super.getPrice()+obj.cost();

    }

    @Override

    public StringgetDescription() {

        return super.description+"-"+super.getPrice()+"&&"+obj.getDescription();

    }

}

4)创建具体装饰接口的实现类Chocolate、Milk,负责具体的装饰

Chocolate代码:

public class Chocolate extends Decorator {

    public Chocolate(Drink obj) {

        super(obj);

        super.setDescription("Chocolate");

        super.setPrice(3.0f);

    }

}

Milk代码:

public class Milkextends Decorator {

public Milk(Drink obj) {

super(obj);

        super.setDescription("Milk");

        super.setPrice(2.0f);

    }

}

5)运行。

若你需要单品咖啡,你可以直接new

Drink order =null;

order =new Decaf();

System.out.println("order one price:"+order.cost());

System.out.println("order one desc:"+order.getDescription());

运行结果:

order one price:3.0

order one desc:Decaf-3.0

若你需要巧克力+牛奶+decaf,你可以现new一个单品(具体组件角色),然后利用装饰接口实现类进行装饰

Drink order =null;

order =new Decaf();

order =new Chocolate(order);

order =new Milk(order);

System.out.println("order two price:"+order.cost());

System.out.println("order two desc:"+order.getDescription());

运行结果:

order two price:8.0

order two desc:Milk-2.0&&Chocolate-3.0&&Decaf-3.0

以后需要怎样搭配就用装饰接口的实现类装饰具体饮料就行,这就解决了前面传统面向对象方式出现的问题,每新出一种混合饮料,都要新建一个混合饮料类的问题。

4、装饰模式概念

1)装饰者模式

    动态地将功能附加到对象上,在对象功能扩展方面,它比继承更有弹性。装饰者模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一种替代方案。

2)装饰者模式的结构

3)装饰者模式的角色和职责

    1、抽象组件角色:一个抽象接口,是被装饰类和被装饰类继承的父接口(本例中的抽象组件角色是Drink)

    2、具体组件角色:为抽象组件的实现类(本例中的具体组件角色是Coffee)

    3、抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口(本例中的抽象装饰角色是Decorator)

    4、具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。(本例中的具体装饰角色是Milk和Chocolate)

5、jdk中的装饰者模式

    我们来看下java中的I/O类

    

接下来我们分析下,这些类充当的装饰者模式中的角色与职责

1)InputStream:这无疑是抽象组件角色,顶级接口

2)FileInputStream/StringBufferInputStream/ByteArrayInputStream:这些类是具体组件角色,是被装饰者角色

3)FilterInputStream:这个类是抽象装饰角色,是装饰者角色

4)BufferInputStream/DataInputStream/LineNumberInputStream:这些类是具体装饰角色,负责具体的装饰。

接着我们自己实现一个具体的装饰角色,自己编写一个自己的I/O装饰者,这个装饰者的功能是读取文件的字符全部大写

1)继承装饰者角色FilterInputStream

2)重写int read()方法和int read(byte[] b, int offset, int len)方法

public class UpperCaseInputStreamextends FilterInputStream {

public UpperCaseInputStream(InputStream in) {

super(in);

    }

@Override

    public int read()throws IOException {

int c =super.read();

        return c==-1?c:Character.toUpperCase((char)c);

    }

@Override

    public int read(byte[] b, int offset, int len)throws IOException {

int result=super.read(b,offset,len);

        for(int i=0;i

b[i]=(byte)Character.toUpperCase((char)(b[i]));

        }

return result;

    }

}

3)运行

public static void main(String[] args) {

int c =0;

    InputStream inputStream =null;

    try {

inputStream =new UpperCaseInputStream(new BufferedInputStream(new FileInputStream("D:\\test.txt")));

        while((c=inputStream.read())>=0) {

System.out.print((char)c);

        }

}catch (IOException e) {

e.printStackTrace();

    }finally {

try {

inputStream.close();

        }catch (IOException e) {

e.printStackTrace();

        }

}

}

运行结果

test.txt文件中的内容

abcdefghjzklmen

运行结果:

ABCDEFGHJZKLMEN

相关文章

  • 如何利用装饰者模式在不改变原有对象的基础上扩展功能

    目录 什么是装饰者模式 普通示例 装饰者模式示例 类图关系 装饰者模式使用场景 装饰者模式优点 装饰者模式缺点 什...

  • 装饰者模式

    装饰者模式 装饰者模式和适配器模式对比 装饰者模式 是一种特别的适配器模式 装饰者与被装饰者都要实现同一个接口,主...

  • java IO 的知识总结

    装饰者模式 因为java的IO是基于装饰者模式设计的,所以要了解掌握IO 必须要先清楚什么事装饰者模式(装饰者模式...

  • 设计模式-装饰者模式

    装饰者模式概念: 装饰者模式又名包装(Wrapper)模式。装饰者模式以对客户端透明的方式扩展对象的功能,是继承关...

  • java - 装饰者模式

    装饰者模式 装饰者模式:动态将责任添加到对象上。如果需要扩展功能,装饰者提供了比继承更有弹性的解决方案。装饰者模式...

  • 设计模式之装饰者模式(Decorator Pattern)

    What: 装饰者模式又名包装(Wrapper)模式。装饰者模式动态地将责任附加到对象身上。若要扩展功能,装饰者提...

  • 装饰者(Decorator)模式

    装饰者(Decorator)模式装饰模式又名包装(Wrapper)模式。装饰模式是继承关系的一个替代方案。装饰模式...

  • 2、装饰者模式

    装饰者模式 一、基本概念 二、结构 三、案例1、装饰者模式案例2、JavaIO中使用装饰者模式 四、总结 一、基本...

  • PHP的设计模式-装饰者模式

    装饰者模式 装饰者模式 装饰者模式类似蛋糕,有草莓味、奶酪等种类,但是它们的核心都是蛋糕。 不断地将对象添加装饰的...

  • 设计模式 | 装饰者模式及典型应用

    前言 本文的主要内容: 介绍装饰者模式 示例 源码分析装饰者模式的典型应用Java I/O 中的装饰者模式spri...

网友评论

      本文标题:装饰者模式

      本文链接:https://www.haomeiwen.com/subject/abizeqtx.html