装饰器模式与代理模式比较

当有这样的业务需求的时候——要为写好的代码在目标代码之前或者之后添加部分操作时,此时最笨的方法就是直接在目标代码的前后加上我们需要的功能代码,但是这样违背了java封装的特性。更好一点的方法就是使用设计模式——代理模式,然而,装饰器模式也有同类的功能,那么着两种设计模式到底有什么区别呢?下面就分别来学习一下这两种设计模式。

装饰器模式类图如下:

该类图包括几个部分:一个接口(装饰器与需要被装饰的实体类都需要实现该接口,公用方法在该接口中定义),一个实现类,一个装饰器的接口,具体实现的装饰器。

在UML图中我们可以到,具体的实现类(需要被装饰的类,ConcreteComponent)与我们的装饰器(Decorator)都实现了相同的接口(Component)。

那么我们来看具体的装饰器模式的代码:

设计模式来源于生活,生活中就有这样的需求,商店每逢遇到不同的节日就会举行不同程度的促销活动,商品的价格也会有不同程度的折扣,假设商品时一个类,那么我们就需要不同的方法来返回商品在不同折扣下的价格了,这时就可以用到设计模式中的装饰器模式。

package DecorateModel;

public interface PriceComponent {
    public float getPrice();
}
package DecorateModel;

public class Good implements PriceComponent{

    private float price=0.0f ;//商品价格

    public Good(float price) {
        this.price = price;
    }

    @Override
    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }
}
package DecorateModel;
/**
 * 半折价格装饰类
 * @author Administrator
 *
 */
public class PriceHalfDecorate implements PriceComponent{

    private Good good ;

    public PriceHalfDecorate(Good good) {
        super();
        this.good = good;
    }

    @Override
    public float getPrice() {
        return this.good.getPrice()/2;
    }
}
package DecorateModel;

public class Price98Decorate implements PriceComponent{

    private Good good ;//需要包装的商品

    public Price98Decorate(Good good) {
this.good = good;
    }

    @Override
    public float getPrice() {
        return this.good.getPrice()*0.98f;
    }
}
package DecorateModel;

public class SaleActivity {        public static void main(String[] args) {        Good shoes = new Good(289f);        //半价促销活动        PriceHalfDecorate halfShoes = new PriceHalfDecorate(shoes);        System.out.println("鞋子价格:"+halfShoes.getPrice());        //98折促销        Price98Decorate price98Shoes  = new Price98Decorate(shoes);        System.out.println("98折鞋子价格:"+price98Shoes.getPrice());    }}    

从上面代码可以看出来,装饰器模式就是通过各种不同的装饰器来装饰我们的目标类,但是目标类和装饰器类都必须实现相同的接口,以便装饰器类知道需要装饰的是哪一个操作(接口中定义的操作,就是装饰器要装饰的操作)。装饰器在java设计中也比较常见,最常见的例如IO流的操作

代理模式的UML类图中可以看出来,代理类和被代理的类也都实现了同一个接口(Subject),接口中定义了需要被代理的方法,在代理类中存在一个被代理对象,并且他们之间的关系是编译时期就已经确定了。

package AgencyModel;

public interface Subject {
    public void sayLove();
}
package AgencyModel;

public class ShyBoy implements Subject{

    @Override
    public void sayLove() {
        System.out.println("小丽,我喜欢你呀!");
    }
}
package AgencyModel;

public class FriendProxy implements Subject{

    private Subject myFriend ;

    public FriendProxy() {
        myFriend = new ShyBoy();
    }

    @Override
    public void sayLove() {
        System.out.println("小丽,我是shyBoy的好朋友!shyBoy让我跟你说");
        myFriend.sayLove();
    }
}

上面的代码描述的就是一个代理的实际情况:一个很害羞的男孩(ShyBoy)非常喜欢小丽这位女孩子,但是有不好意思直接跟小丽表白,因此ShyBoy找到了他的好朋友FriendProxy,让好友代理自己跟小丽表白。因此ShyBoy,FriendProxy都有对小丽表白的方法sayLove(),因此将这个方法抽象到一个接口中,就是我们的Subject接口。因为ShyBoy与FriendProxy是相互认识的,所有只要存在FriendProxy时ShyBoy也一并存在(关系在编译期就确定,在代理类的构造方法中初始化被代理的对象)。

装饰器模式与代理模式的差异:

装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。

转神人解释代理模式与装饰器模式:

代理模式
考虑现实生活中的代理商. 你想要进一批货,但是出于某种原因,你无法直接与生产商联系(有可能是因为你生产商与你相隔太远,
或者比如你进的货是军 火, 一般来说生产商也不会直接露面滴), 这时候你就需要一个代理商, 他能够接受你的订单, 并且也能给你需要的货品,
但是记住,代理商并不真正生产货品,他的能力在于他有办法从生产商那里给你搞到货品.

那么对于买家,也就是接口的调用者而言, 我并不关心你到底是代理商还生产商,我只要你能够跟我交易就可以. 从这角度理解的话,代理隔离了调用者和实现者直接的联系.

实际编码中的例子呢, 比如WebService的调用你就可以把他理解成一个(远程)代理.

装饰模式
语义上理解,装饰是什么呢? 装饰就是在原本的东西上添油加醋嘛. 装饰的原则就是,对于一个西瓜, 不管我怎么装饰,它始终都是一个西瓜, 我不能最终把它装饰一番之后当成土豆去卖.

举个例子,大家应该都买过那种现做的冰淇淋. 一般都是这样卖的, 普通的冰淇淋必选,上面可以加上各种葡萄干啊,榛子啊,蓝莓酱啊之类的,当然每加一样你就要多交一点钱啦:). 那针对这个给冰淇淋算价钱的问题, 写成代码呢, 差不多就是这样子的.
Java代码

//抽象冰淇淋
abstract class AbstractIceCream{
public abstract int getPrice();
}

//真正的冰淇淋
class IceCream extends AbstractIceCream{

public int getPrice(){
return 2; //原味冰淇淋只卖5块~~
}
}
//冰淇淋的巧克力装饰器
class ChocolateAdapter extends AbstractIceCream {
private AbstractIceCream iceCream; //to be adapted.
public ChocolateAdapter(AbstractIceCream iceCream){
this.iceCream = iceCream
}
public getPrice (){
return this.iceCream.getPrice()+3; //假设加一层巧克力要加3块钱好了~
}
}
//冰淇淋的蓝莓酱装饰器
class BlueberryAdapter extends AbstractIceCream {
private AbstractIceCream iceCream; //to be adapted.
public BlueberryAdapter(AbstractIceCream iceCream){
this.iceCream = iceCream
}
public getPrice (){
return this.iceCream.getPrice()+5; //假设加一层蓝莓酱要加5块钱好了~
}
}

//顾客来了
public class Client{
public static void main(String args[]){
//给我来个蓝莓冰淇淋
AbstractIceCream blueberryIceCream = new BlueberryAdapter(new IceCream());

//给我来个蓝莓巧克力冰淇淋~~
AbstractIceCream bb_ch_iceCream = new BlueberryAdapter(new ChocolateAdapter(new IceCream()));

//来了一个巧克力超级粉丝说,我要加3层巧克力~~
AbstractIceCream lot_of_chocolate_iceCream = new
ChocolateAdapter(new ChocolateAdapter(new ChocolateAdapter(new
IceCream())))

//然后算帐看看,你猜这些冰淇淋分别要多少钱呢...
println(blueberryIceCream.getPrice());
println(bb_ch_iceCream.getPrice());
println(lot_of_chocolate_iceCream.getPrice());

}
}


成这样我想大家应该能理解了? 再啰嗦两句,装饰器模式实际上在一定程度上解决了一个问题, 那就是类继承的局限性,类爆炸.
像上面的例子中,用最原始的集成方案的话,大概需要一下几个类: 冰淇淋, 巧克力的冰淇淋, 草莓的冰淇淋,
巧克力和草莓都有的冰淇淋...貌似还可以接受,但由于这些辅料是可以随意组合的, 那么比如我又新添了一个辅料香草,那我就又要新增 N个子类...,
学过组合数学的同学就会知道, 其实没学的也知道, 这样一来子类的生长速度可是相当客观的. 而使用装饰器的话,
新增一个辅料,我只需新增一个装饰器类即可, 省心啊...看起来程序员的生活又美好了不是么?

ok, 我保证这是最后一句啰嗦:
所谓模式,其实就是最佳实践的总结. 所以要学透模式,一定要联系现实生活,先弄清楚什么情况下需要使用这个模式,否则凭空想象的话,很容易混淆不说,还抓不住精要.

时间: 2024-11-03 21:14:10

装饰器模式与代理模式比较的相关文章

设计模式回顾:策略模式、代理模式、装饰者模式的区别

前言 设计模式有很多,但设计模式的目的是一致的,都是为了提升代码的可读性和可扩展性.设计模式都遵循一些基本的原则,设计模式是为了遵循这些原则而创造的工具. - 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因.这一点是说,如果有一些类过于臃肿,承担了过多的职责,就应当分解他. - 开放-封闭原则:软件实体(类.模块.函数等)应该可以扩展,但是不可修改.这一点是说,拒绝硬编码,拒绝直接修改原有代码. - 依赖倒转原则:高层模块不应该以来低层模块.两个都应该以来抽象.抽象不应该依赖细节.细节

Java进阶篇设计模式之七 ----- 享元模式和代理模式

前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. 用通俗的话来说就是进行共用.生活中也有一些例子,比如之前很火的共享单车,更早之前的图书馆,编程中经常用的String类,数据库连接池等等.当然,享元模式主要的目的是复用,如果该对象没有的话,就会进行创建. 享

Java-设计模式之代理模式

1.什么是代理模式? 代理模式就是为其他对象提供一种代理,以控制对这个对象的访问.例如我们在购买火车票的时候,在有些地方有火车票的代售点,这些代售点可以帮助火车站来实行购票的功能,像这种模式就是代理模式.在Java中,代理模式启动中介的作用,可以去掉功能服务或者增加额外的服务. 2.代码模式的分类 A.远程代理:为不同地理的对象提供局域网代表对象,相似于客户端和服务器一样的模式. B.虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建.例如,在我们浏览网页的时候,有时候需要加

结构型模式之代理模式

概述 在软件开发中,有一种设计模式可以提供与代购网站类似的功能.由于某些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称之为“代理”的第三者来实现间接访问,该方案对应的设计模式被称为代理模式. 代理模式是一种应用很广泛的结构型设计模式,而且变化形式非常多,常见的代理形式包括远程代理.保护代理.虚拟代理.缓冲代理.智能引用代理等. 定义 代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问. 实现 /// <summary> /// 供应商 /// </s

Java代理模式——静态代理模式

一:代理模式 代理模式的作用是:为其他对象提供一种代理以控制这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 二:代理模式设计到的角色 抽象角色:声明真是对象和代理对象的共同接口(抽象类或接口). 代理角色:代理对象角色内部含有对真是对象的引用,从而可以操作真是对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真是对象.同时,代理对象可以在执行真实对象的操作时,附加其他操作,相当于对真是对象进行封装. 真实

结构型模式:代理模式

文章首发: 结构型模式:代理模式 七大结构型模式之七:代理模式. 简介 姓名 :代理模式 英文名 :Proxy Pattern 价值观 :为生活加点料 个人介绍 : Provide a surrogate or placeholder for another object to control access to it. 为其他对象提供一种代理以控制对这个对象的访问. (来自<设计模式之禅>) 你要的故事 咱们从事 IT 行业,随时都可能上网查东西,如果网络速度慢或者网络访问受限制,那是相当的

装饰器模式和代理模式区别

代理模式和装饰者模式上在语法形式上几乎完全一样,那么它们的区别在哪里呢? 装饰者模式:动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更加灵活 代理模式:为其它对象提供一种代理以控制对这个对象的访问. 其实,它们的着重点一个在于“增加”职责,另一个在于“控制”访问.这是它们最本质的区别.

装饰器(Decorator)模式

1  装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能.通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式.显然,直接修改对应的类这种方式并不可取.在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能.装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能.装饰器模式的本质就是动态组合.动态是手段,组合才是目的.总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需

4 结构型模式之 - 代理模式

代理模式的介绍:代理模式也称为委托模式,在开发中经常用到,是编程的好帮手,在日常生活中也比较常见.比如公司中午让同事帮忙带一份饭,比如我们请一个律师打官司,比如我们用代理服务器上网等等.代理模式真是无处不在. 代理模式的定义:为其它对象提供一种代理以控制对这个对象的访问. 代理模式的使用场景:当无法或者不想直接访问某个对象或者访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象或者代理对象需要实现相同的接口. 代理模式一般的写法(静态代理模式): 代理类和