Java23中设计模式之”装饰者模式”
来源:互联网 发布:第一网红 知乎 编辑:程序博客网 时间:2024/06/06 02:42
目录:
一 “开放-闭合原则”(开闭原则)
二 什么是“装饰者模式”--图解
三 “装饰者模式”实例--星笆兹饮料厂
四 没有完美的设计模式--“装饰模式的不足之处”
一“开放-闭合原则”(开闭原则)
开闭原则: 类应该对拓展开放, 对修改关闭. 听起来好像不太舒服, 类既然需要”拓展’,怎么会不需要修改呢? 开闭原则针对类; 不修改类, 但是需要拓展功能. 使用继承的方式通常是做不到的, 原因是: 继承在编译时决定”行为”, 不是在运行时动态修改行为,也就是所谓的”拓展”,继承的原因是”行为复用”, 不足之处是无法动态拓行为(缺少弹性).
<head first 设计模式>:
我们的目的是允许类容易拓展, 在不修改代码的情况下, 就可以匹配新的行为, 这样的设计具有弹性可以应对变化,可以接受新的功能应对改变的需求
通常实现开闭原则的方式不止一种, 装饰者模式是很好的例子! 我自己认为: 实现开闭原则要注意以下00(面向对象)原则
(1)面向接口(接口或者抽象类)编程,
(2)多用组合, 少用继承
举个例子:
//使用Person的客户
public class ObserverDesign{
Person person;
public ObserverDesign() {
}
public void setPerson(Personp){
this.person=p;
}
public void sayOK(){
person.say();
}
}
//Person接口
interface Person{
void say();
}
//Student类
class Student implements Person {
@Override
public void say() {
System.out.println("I am a student");
}
}
//Teacher0000000000000000类
class Teacher implements Person {
@Override
public void say() {
System.out.println("I am a Teacher");
}
}
ObserverDesign类符合”开闭原则”, ObserverDesign从来不关心Person是哪个具体实例,只关心执行sayOK行为,我们测试一下
public class Design{
public static void main(String[] args) {
//创建ObserverDesign
ObserverDesign obj=new ObserverDesign();
//student
Student stu=new Student();
//teacher
Teacher teacher=new Teacher();
//动态设置属性
obj.setPerson(stu);
obj.sayOK();
//修改
obj.setPerson(teacher);
obj.sayOK();
}
}
二 什么是“装饰者模式”--图解
(1)装饰者模式定义: 动态地将责任附加到对象上,若要拓展功能,装饰者提供比继承更有弹性的替代方案
(2)来自<head first 设计模式>的一张实现类图(自己不想画图)
其中Decorate是装饰者抽象接口, ConcreteDecoratorA、ConcreteDecoratorB是
”装饰者”类, ConcreteComponent是”被装饰者”
三“装饰者模式”实例--星笆兹饮料厂
这个案例来自<head first 设计模式>, 购买饮料时, 我们可以要求在其中加各种不同的调料(变化), 比如买一杯鲜果奶茶, 可以要求在里面加苹果汁、哈密瓜汁、奶酪等调料。
我们还需要计算出饮料+调料的总价钱(没学习设计模式之前你会怎么做? 看看你的程序有没足够的弹性, 又有多少依赖)
下面我们使用”装饰者模式”定义的类图来编码:
首先我们需要一个饮料抽象类, 装饰者和被装饰者都要直接或者间接实现该接口, 想想我们Java中IO流学习时, 我们是不是经常使用BufferInputStream"替换"InputStream? 因为他们实现了统一的接口(类型一致). 装饰者对象替换被装饰对象inputStream,并且拓展了他的功能。所以我们需要实现统一接口。 代码如下:
饮料抽象接口
public abstract class Beverage{
protected String desc="unkonw";
//实现
public String getDescription(){
return desc;
}
//抽象,计算价格
public abstract double cost();
}
2个具体的饮料
import cn.design.decorate.inter.Beverage;
public class Espressoextends Beverage{
public Espresso(){
desc="Espresso";
}
@Override
public double cost() {
return 1.2;
}
//设置饮料描述
public void setDesc(Stringdesc) {
this.desc=desc;
}
}
package cn.design.decorate;
import cn.design.decorate.inter.Beverage;
public class HouseBlendextends Beverage{
public HouseBlend() {
desc="HouseBlend";
}
@Override
public double cost() {
return 0.8;
}
//设置饮料描述
public void setDesc(Stringdesc) {
this.desc=desc;
}
}
现在: 饮料抽象接口有了, 具体的饮料也有了,现在我们来实现装饰者
首先,来一个抽象接口
package cn.design.decorate.inter;
public abstract class CondimentDecorateextends Beverage{
//从新定义描述行为
public abstract String getDescription();
}
具体的装饰者---调料
package cn.design.decorate;
import cn.design.decorate.inter.Beverage;
import cn.design.decorate.inter.CondimentDecorate;
public class Mochaextends CondimentDecorate{
//被装饰者: 饮料
private Beverage beverage;
//设置饮料具体实现---但是Mocha装饰者不关心是那种饮料
public void setBeverage(Beveragebeverage) {
this.beverage =beverage;
}
//构造器,初始化beverage
public Mocha(Beveragebeverage) {
this.beverage=beverage;
}
//构造器: 也可以什么都不做
public Mocha() {
}
@Override
public String getDescription() {
//被装饰饮料描述 + 装饰者调料描述(可以通过设置变量来修改)
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
//价钱: 被装饰饮料价钱 + 装饰者调料价钱
return beverage.cost()+ 0.6;
}
}
package cn.design.decorate;
import cn.design.decorate.inter.Beverage;
import cn.design.decorate.inter.CondimentDecorate;
public class Whipextends CondimentDecorate{
//被装饰者: 饮料
private Beverage beverage;
//设置饮料具体实现---但是Whip装饰者不关心是那种饮料
public void setBeverage(Beveragebeverage) {
this.beverage =beverage;
}
//构造器,初始化beverage
public Whip(Beveragebeverage) {
this.beverage=beverage;
}
//构造器: 也可以什么都不做
public Whip() {
}
@Override
public String getDescription() {
//被装饰饮料描述 + 装饰者调料描述(可以通过设置变量来修改)
return beverage.getDescription()+",Whip";
}
@Override
public double cost() {
//价钱: 被装饰饮料价钱 + 装饰者调料价钱
return beverage.cost()+ 1.2;
}
}
一切顺利准备好了, 现在我们坐下来喝点饮料. 你想要什么调料的饮料?
package cn.design.decorate;
import cn.design.decorate.inter.Beverage;
/*
* “策略模式”
* */
public class Client{
public static void main(String[] args) {
//(1)用Mocha装饰Espresso饮料
Beverage beverage=new Mocha(new Espresso());
System.out.println("Description:"+beverage.getDescription());
System.out.println("cost:"+beverage.cost());
System.out.println("````````````````");
//(2)Espresso饮料中含有Mocha, 再加点Whip会不会更加美味?
beverage=new Whip(beverage);
System.out.println("Description:"+beverage.getDescription());
System.out.println("cost:"+beverage.cost());
}
}
例子(2)是带有Mocha ,whip的Espresso饮料。我们的
Beverage beverage=new Mocha(new Espresso()); 想不想: BufferedInputStreamis=new BufferedInputStream(new InputStream(){..});
总结: 代码终于写完了,简单运用了一下"装饰者模式",代码看起来好像舒服一些.
一 现在来看看, 我们的装饰者类是符合开闭原则的,再不要修改代码的情况下, 可以动态改变"被装饰者"来拓展行为.
四 没有完美的设计模式--“装饰模式的不足之处”
Java的23种设计模式或多或少都是存在不足之处的,就像我们程序员,可能在某些技术或者管理方面存在不足, 但是这不影响我们使用模式. 装饰者模式不足之处应该也有,比如上面的例子中, 饮料要是在双十一打折呢?需要对具体的被装饰者编程时,由于在装饰者中修改了这个具体,使用了统一接口(接口中没有具体的函数定义)。这是要去"修改"代码吗?在实际开发中应该根据具体情况来处理, 而我们的"装饰者"的创建也可以交给工厂模式或者生成器管理!
- Java23中设计模式之”装饰者模式”
- Android的开发之&java23中设计模式------>装饰模式
- java23种常用设计模式之装饰模式(Decorator)
- java23种设计模式之装饰模式(Decorator)
- java23种设计模式之装饰器模式
- java23中设计模式之工厂模式
- java23中设计模式之代理模式
- java23中设计模式
- java23中设计模式
- java23中设计模式
- Android的开发之&java23中设计模式------>工厂模式
- Android的开发之&java23中设计模式------>原型模式
- Android的开发之&java23中设计模式------>代理模式
- Android的开发之&java23中设计模式------>外观模式
- Android的开发之&java23中设计模式------>组合模式
- java23种设计模式--装饰模式(decorator)
- Java23种设计模式——装饰模式
- java23种设计模式之建造者模式(Builder)
- 搭建大型源码阅读环境——使用 OpenGrok 搭建大型源码阅读环境——使用 OpenGrok
- 数据库SQL语句练习题
- 设计模式--观察者模式初探和java Observable模式
- 不值一提的计算机基础教程-1-文件
- Android笔记(二):网络图片加载器
- Java23中设计模式之”装饰者模式”
- 双11黑科技,阿里百万级服务器自动化运维系统StarAgent揭秘
- php自动生成数据字典
- 在ASP.NET中的JQuery FullCalendar实现
- ARM的体系结构变种
- 关于Spring的<context:annotation-config/>配置详解
- 1.基本按钮样式
- spring boot 事物管理
- Tomcat8部署方式(未完待续)