结构模式.docx

上传人:b****8 文档编号:29233199 上传时间:2023-07-21 格式:DOCX 页数:28 大小:32.30KB
下载 相关 举报
结构模式.docx_第1页
第1页 / 共28页
结构模式.docx_第2页
第2页 / 共28页
结构模式.docx_第3页
第3页 / 共28页
结构模式.docx_第4页
第4页 / 共28页
结构模式.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

结构模式.docx

《结构模式.docx》由会员分享,可在线阅读,更多相关《结构模式.docx(28页珍藏版)》请在冰豆网上搜索。

结构模式.docx

结构模式

设计模式之Adapter(适配器)

定义:

将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份.

为何使用?

我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:

修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。

怎么办?

使用Adapter,在这两种接口之间创建一个混合接口(混血儿).

如何使用?

实现Adapter方式,其实"thinkinJava"的"类再生"一节中已经提到,有两种方式:

组合(composition)和继承(inheritance).

假设我们要打桩,有两种类:

方形桩圆形桩.

publicclassSquarePeg{

  publicvoidinsert(Stringstr){

    System.out.println("SquarePeginsert():

"+str);

  }

}

publicclassRoundPeg{

  publicvoidinsertIntohole(Stringmsg){

    System.out.println("RoundPeginsertIntoHole():

"+msg);

}

}

现在有一个应用,需要既打方形桩,又打圆形桩.那么我们需要将这两个没有关系的类综合应用.假设RoundPeg我们没有源代码,或源代码我们不想修改,那么我们使用Adapter来实现这个应用:

publicclassPegAdapterextendsSquarePeg{

  privateRoundPegroundPeg;

  publicPegAdapter(RoundPegpeg)(this.roundPeg=peg;)

  publicvoidinsert(Stringstr){roundPeg.insertIntoHole(str);}

}

在上面代码中,RoundPeg属于Adaptee,是被适配者.PegAdapter是Adapter,将Adaptee(被适配者RoundPeg)和Target(目标SquarePeg)进行适配.实际上这是将组合方法(composition)和继承(inheritance)方法综合运用.

PegAdapter首先继承SquarePeg,然后使用new的组合生成对象方式,生成RoundPeg的对象roundPeg,再重载父类insert()方法。

从这里,你也了解使用new生成对象和使用extends继承生成对象的不同,前者无需对原来的类修改,甚至无需要知道其内部结构和源代码.

如果你有些Java使用的经验,已经发现,这种模式经常使用。

进一步使用

上面的PegAdapter是继承了SquarePeg,如果我们需要两边继承,即继承SquarePeg又继承RoundPeg,因为Java中不允许多继承,但是我们可以实现(implements)两个接口(interface)

publicinterfaceIRoundPeg{

  publicvoidinsertIntoHole(Stringmsg);

}

publicinterfaceISquarePeg{

  publicvoidinsert(Stringstr);

}

下面是新的RoundPeg和SquarePeg,除了实现接口这一区别,和上面的没什么区别。

publicclassSquarePegimplementsISquarePeg{

  publicvoidinsert(Stringstr){

    System.out.println("SquarePeginsert():

"+str);

  }

}

publicclassRoundPegimplementsIRoundPeg{

  publicvoidinsertIntohole(Stringmsg){

    System.out.println("RoundPeginsertIntoHole():

"+msg);

  }

}

下面是新的PegAdapter,叫做two-wayadapter:

publicclassPegAdapterimplementsIRoundPeg,ISquarePeg{

  privateRoundPegroundPeg;

  privateSquarePegsquarePeg;

  //构造方法

  publicPegAdapter(RoundPegpeg){this.roundPeg=peg;}

  //构造方法

  publicPegAdapter(SquarePegpeg)(this.squarePeg=peg;)

  publicvoidinsert(Stringstr){roundPeg.insertIntoHole(str);}

}

还有一种叫PluggableAdapters,可以动态的获取几个adapters中一个。

使用Reflection技术,可以动态的发现类中的Public方法。

设计模式之Bridge

Bridge定义:

将抽象和行为划分开来,各自独立,但能动态的结合.

为什么使用?

通常,当一个抽象类或接口有多个具体实现(concretesubclass),这些concrete之间关系可能有以下两种:

1.这多个具体实现之间恰好是并列的,如前面举例,打桩,有两个concreteclass:

方形桩和圆形桩;这两个形状上的桩是并列的,没有概念上的重复,那么我们只要使用继承就可以了.

2.实际应用上,常常有可能在这多个concreteclass之间有概念上重叠.那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象和行为.

例如,一杯咖啡为例,有中杯和大杯之分,同时还有加奶不加奶之分.如果用单纯的继承,这四个具体实现(中杯大杯加奶不加奶)之间有概念重叠,因为有中杯加奶,也有中杯不加奶,如果再在中杯这一层再实现两个继承,很显然混乱,扩展性极差.那我们使用Bridge模式来实现它.

如何实现?

以上面提到的咖啡为例.我们原来打算只设计一个接口(抽象类),使用Bridge模式后,我们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口.

先看看抽象部分的接口代码:

publicabstractclassCoffee

{

  CoffeeImpcoffeeImp;

  publicvoidsetCoffeeImp(){

    this.CoffeeImp=CoffeeImpSingleton.getTheCoffeImp();

  }

  publicCoffeeImpgetCoffeeImp(){returnthis.CoffeeImp;}

  publicabstractvoidpourCoffee();

}

其中CoffeeImp是加不加奶的行为接口,看其代码如下:

publicabstractclassCoffeeImp

{

  publicabstractvoidpourCoffeeImp();

}

现在我们有了两个抽象类,下面我们分别对其进行继承,实现concreteclass:

//中杯

publicclassMediumCoffeeextendsCoffee

{

  publicMediumCoffee(){setCoffeeImp();}

  publicvoidpourCoffee()

  {

    CoffeeImpcoffeeImp=this.getCoffeeImp();

    //我们以重复次数来说明是冲中杯还是大杯,重复2次是中杯

    for(inti=0;i<2;i++)

    {

      coffeeImp.pourCoffeeImp();

    }

  

  }

}

//大杯

publicclassSuperSizeCoffeeextendsCoffee

{

  publicSuperSizeCoffee(){setCoffeeImp();}

  publicvoidpourCoffee()

  {

    CoffeeImpcoffeeImp=this.getCoffeeImp();

    //我们以重复次数来说明是冲中杯还是大杯,重复5次是大杯

    for(inti=0;i<5;i++)

    {

      coffeeImp.pourCoffeeImp();

    }

  

  }

}

上面分别是中杯和大杯的具体实现.下面再对行为CoffeeImp进行继承:

//加奶

publicclassMilkCoffeeImpextendsCoffeeImp

{

  MilkCoffeeImp(){}

  publicvoidpourCoffeeImp()

  {

    System.out.println("加了美味的牛奶");

  }

}

//不加奶

publicclassFragrantCoffeeImpextendsCoffeeImp

{

  FragrantCoffeeImp(){}

  publicvoidpourCoffeeImp()

  {

    System.out.println("什么也没加,清香");

  }

}

Bridge模式的基本框架我们已经搭好了,别忘记定义中还有一句:

动态结合,我们现在可以喝到至少四种咖啡:

1.中杯加奶

2.中杯不加奶

3.大杯加奶

4.大杯不加奶

看看是如何动态结合的,在使用之前,我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:

publicclassCoffeeImpSingleton

{

  privatestaticCoffeeImpcoffeeImp;

  publicCoffeeImpSingleton(CoffeeImpcoffeeImpIn)

  {this.coffeeImp=coffeeImpIn;}

  publicstaticCoffeeImpgetTheCoffeeImp()

  {

    returncoffeeImp;

  }

}

看看中杯加奶和大杯加奶是怎么出来的:

//拿出牛奶

CoffeeImpSingletoncoffeeImpSingleton=newCoffeeImpSingleton(newMilkCoffeeImp());

//中杯加奶

MediumCoffeemediumCoffee=newMediumCoffee();

mediumCoffee.pourCoffee();

//大杯加奶

SuperSizeCoffeesuperSizeCoffee=newSuperSizeCoffee();

superSizeCoffee.pourCoffee();

注意:

Bridge模式的执行类如CoffeeImp和Coffee是一对一的关系,正确创建CoffeeImp是该模式的关键,

Bridge模式在EJB中的应用

EJB中有一个DataAccessObject(DAO)模式,这是将商业逻辑和具体数据资源分开的,因为不同的数据库有不同的数据库操作.将操作不同数据库的行为独立抽象成一个行为接口DAO.如下:

1.BusinessObject(类似Coffee)

实现一些抽象的商业操作:

如寻找一个用户下所有的订单

涉及数据库操作都使用DAOImplementor.

2.DataAccessObject(类似CoffeeImp)

一些抽象的对数据库资源操作

3.DAOImplementor如OrderDAOCS,OrderDAOOracle,OrderDAOSybase(类似MilkCoffeeImpFragrantCoffeeImp)

具体的数据库操作,如"INSERTINTO"等语句,OrderDAOOracle是OracleOrderDAOSybase是Sybase数据库.

4.数据库(Cloudscape,Oracle,orSybasedatabaseviaJDBCAPI)

设计模式之Composite(组合)

板桥里人2002/04/27

Composite定义:

将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性.

Composite比较容易理解,想到Composite就应该想到树形结构图。

组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行。

可以用牵一动百来形容。

所以Composite模式使用到Iterator模式,和ChainofResponsibility模式类似。

Composite好处:

1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。

2.更容易在组合体内加入对象部件.客户端不必因为加入了新的对象部件而更改代码。

如何使用Composite?

首先定义一个接口或抽象类,这是设计模式通用方式了,其他设计模式对接口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和管理Composite组合体的对象们(或称部件Component).

下面的代码是以抽象类定义,一般尽量用接口interface,

publicabstractclassEquipment

{

  privateStringname;

  //网络价格

  publicabstractdoublenetPrice();

  //折扣价格

  publicabstractdoublediscountPrice();

  //增加部件方法  

  publicbooleanadd(Equipmentequipment){returnfalse;}

  //删除部件方法

  publicbooleanremove(Equipmentequipment){returnfalse;}

  //注意这里,这里就提供一种用于访问组合体类的部件方法。

  publicIteratoriter(){returnnull;}

  

  publicEquipment(finalStringname){this.name=name;}

}

抽象类Equipment就是Component定义,代表着组合体类的对象们,Equipment中定义几个共同的方法。

publicclassDiskextendsEquipment

{

  publicDisk(Stringname){super(name);}

  //定义Disk网络价格为1

  publicdoublenetPrice(){return1.;}

  //定义了disk折扣价格是0.5对折。

  publicdoublediscountPrice(){return.5;}

}

Disk是组合体内的一个对象,或称一个部件,这个部件是个单独元素(Primitive)。

还有一种可能是,一个部件也是一个组合体,就是说这个部件下面还有'儿子',这是树形结构中通常的情况,应该比较容易理解。

现在我们先要定义这个组合体:

abstractclassCompositeEquipmentextendsEquipment

{

  privateinti=0;

  //定义一个Vector用来存放'儿子'

  privateLsitequipment=newArrayList();

  publicCompositeEquipment(Stringname){super(name);}

  publicbooleanadd(Equipmentequipment){

    this.equipment.add(equipment);

    returntrue;

  }

  publicdoublenetPrice()

  {

    doublenetPrice=0.;

    Iteratoriter=equipment.iterator();

    for(iter.hasNext())

      netPrice+=((Equipment)iter.next()).netPrice();

    returnnetPrice;

  }

  publicdoublediscountPrice()

  {

    doublediscountPrice=0.;

    Iteratoriter=equipment.iterator();

    for(iter.hasNext())

      discountPrice+=((Equipment)iter.next()).discountPrice();

    returndiscountPrice;

  }

  

  //注意这里,这里就提供用于访问自己组合体内的部件方法。

  //上面dIsk之所以没有,是因为Disk是个单独(Primitive)的元素.

  publicIteratoriter()

  {

    returnequipment.iterator();

  {

  //重载Iterator方法

  publicbooleanhasNext(){returni

  //重载Iterator方法

  publicObjectnext()

  {

    if(hasNext())

      returnequipment.elementAt(i++);

    else

     thrownewNoSuchElementException();

  }

  

}

上面CompositeEquipment继承了Equipment,同时为自己里面的对象们提供了外部访问的方法,重载了Iterator,Iterator是Java的Collection的一个接口,是Iterator模式的实现.

我们再看看CompositeEquipment的两个具体类:

盘盒Chassis和箱子Cabinet,箱子里面可以放很多东西,如底板,电源盒,硬盘盒等;盘盒里面可以放一些小设备,如硬盘软驱等。

无疑这两个都是属于组合体性质的。

publicclassChassisextendsCompositeEquipment

{

  publicChassis(Stringname){super(name);}

  publicdoublenetPrice(){return1.+Price();}

  publicdoublediscountPrice(){return.5+super.discountPrice();}

}

publicclassCabinetextendsCompositeEquipment

{

  publicCabinet(Stringname){super(name);}

  publicdoublenetPrice(){return1.+Price();}

  publicdoublediscountPrice(){return.5+super.discountPrice();}

}

至此我们完成了整个Composite模式的架构。

我们可以看看客户端调用Composote代码:

Cabinetcabinet=newCabinet("Tower");

Chassischassis=newChassis("PCChassis");

//将PCChassis装到Tower中(将盘盒装到箱子里)

cabinet.add(chassis);

//将一个10GB的硬盘装到PCChassis(将硬盘装到盘盒里)

chassis.add(newDisk("10GB"));

//调用netPrice()方法;

System.out.println("netPrice="+Price());

System.out.println("discountPrice="+cabinet.discountPrice());

上面调用的方法netPrice()或discountPrice(),实际上Composite使用Iterator遍历了整个树形结构,寻找同样包含这个方法的对象并实现调用执行.

Composite是个很巧妙体现智慧的模式,在实际应用中,如果碰到树形结构,我们就可以尝试是否可以使用这个模式。

以论坛为例,一个版(forum)中有很多帖子(message),这些帖子有原始贴,有对原始贴的回应贴,是个典型的树形结构,那么当然可以使用Composite模式,那么我们进入Jive中看看,是如何实现的.

Jive解剖

在Jive中ForumThread是ForumMessages的容器container(组合体).也就是说,ForumThread类似我们上例中的CompositeEquipment.它和messages的关系如图:

[thread]

  |-[message]

  |-[message]

    |-[message]

    |-[message]

      |-[message]

我们在ForumThread看到如下代码:

publicinterfaceForumThread{

  ....

  publicvoidaddMessage(ForumMessageparentMessage,ForumMessagenewMessage)

      throwsUnauthorizedException;

  publicvoiddeleteMessage(ForumMessagemessage)

      throwsUnauthorizedExceptio

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1