设计模式大类--结构模式(下)

五、Decorate(装饰者)
描述:动态的给一个对象添加额外的职责,比继承达到更好的灵活性
好处:某些功能需要用户动态决定加入方式和时机,装饰者提供即插即用的模型

例子:
举Adapter中的打桩示例,在Adapter中有两种类:方形桩
圆形桩,Adapter模式展示如何综合使用这两个类,在Decorator模式中,我们是要在打桩时增加一些额外功能,比如,挖坑
在桩上钉木板等,不关心如何使用两个不相关的类
我们先建立一个接口:
public interface Work
{
  public
void insert();

}

接口Work有一个具体实现:插入方形桩或圆形桩,这两个区别对Decorator是无所谓.我们以插入方形桩为例:
public class
SquarePeg implements Work{
  public void
insert(){
    System.out.println("方形桩插入");
  }

}

现在有一个应用:需要在桩打入前,挖坑,在打入后,在桩上钉木板,这些额外的功能是动态,可能随意增加调整修改,比如,可能又需要在打桩之后钉架子(只是比喻).
那么我们使用Decorator模式,这里方形桩SquarePeg是decoratee(被装饰者),我们需要在decoratee上加些"装饰",这些装饰就是那些额外的功能.
public
class Decorator implements Work{

  private Work work;
  //额外增加的功能被打包在这个List中
  private ArrayList others
= new ArrayList();

  //在构造器中使用组合new方式,引入Work对象;
  public Decorator(Work
work)
  {
    this.work=work;
  
    others.add("挖坑");

    others.add("钉木板");
  }

  public void insert(){

    newMethod();
  }

  
  //在新方法中,我们在insert之前增加其他方法,这里次序先后是用户灵活指定的   
  public void
newMethod()
  {
    otherMethod();
    work.insert();

  }

  public void otherMethod()
  {
    ListIterator listIterator =
others.listIterator();
    while
(listIterator.hasNext())
    {
      System.out.println(((String)(listIterator.next()))
+ " 正在进行");
    }

  }

}

在上例中,我们把挖坑和钉木板都排在了打桩insert前面,这里只是举例说明额外功能次序可以任意安排.

好了,Decorator模式出来了,我们看如何调用:

Work squarePeg = new SquarePeg();
Work decorator = new
Decorator(squarePeg);
decorator.insert();

Decorator模式至此完成.

如果你细心,会发现,上面调用类似我们读取文件时的调用:

FileReader fr = new FileReader(filename);
BufferedReader br = new
BufferedReader(fr);

实际上Java 的I/O API就是使用Decorator实现的,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐.

六、Bridege(桥接)
描述:将抽象和行为划分开,各自独立,但能动态结合
好处:多个concrete
class之间有概念上重叠.那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口,分别放置抽象和行为

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

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

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

public abstract class Coffee
{
  CoffeeImp coffeeImp;

  public void setCoffeeImp() {
    this.CoffeeImp =
CoffeeImpSingleton.getTheCoffeImp();
  }

  public CoffeeImp getCoffeeImp() {return this.CoffeeImp;}

  public abstract void pourCoffee();
}

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

public abstract class CoffeeImp
{
  public abstract void
pourCoffeeImp();
}

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

//中杯
public class MediumCoffee extends Coffee
{
  public
MediumCoffee() {setCoffeeImp();}

  public void pourCoffee()
  {
    CoffeeImp coffeeImp =
this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复2次是中杯
    for (int i = 0;
i < 2; i++)
    {

      coffeeImp.pourCoffeeImp();
    }
  
  }
}

//大杯
public class SuperSizeCoffee extends Coffee
{
  public
SuperSizeCoffee() {setCoffeeImp();}

  public void pourCoffee()
  {
    CoffeeImp coffeeImp =
this.getCoffeeImp();
    //我们以重复次数来说明是冲中杯还是大杯 ,重复5次是大杯
    for (int i = 0;
i < 5; i++)
    {

      coffeeImp.pourCoffeeImp();
    }
  
  }
}

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

//加奶
public class MilkCoffeeImp extends
CoffeeImp
{
  MilkCoffeeImp() {}

  public void
pourCoffeeImp()
  {
    System.out.println("加了美味的牛奶");
  }
}

//不加奶
public class FragrantCoffeeImp extends
CoffeeImp
{
  FragrantCoffeeImp() {}

  public void
pourCoffeeImp()
  {
    System.out.println("什么也没加,清香");
  }
}

Bridge模式的基本框架我们已经搭好了,别忘记定义中还有一句:动态结合,我们现在可以喝到至少四种咖啡:
1.中杯加奶
2.中杯不加奶
3.大杯加奶
4.大杯不加奶

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

public class CoffeeImpSingleton
{
  private static CoffeeImp
coffeeImp;

  public CoffeeImpSingleton(CoffeeImp coffeeImpIn)
   {this.coffeeImp =
coffeeImpIn;}

  public static CoffeeImp getTheCoffeeImp()
  {
    return
coffeeImp;
  }
}

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

//拿出牛奶
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new
MilkCoffeeImp());

//中杯加奶
MediumCoffee mediumCoffee = new
MediumCoffee();
mediumCoffee.pourCoffee();

//大杯加奶
SuperSizeCoffee superSizeCoffee = new
SuperSizeCoffee();
superSizeCoffee.pourCoffee();

七、Flyweight(享元)
描述:运用共享技术有效的支持大量细粒度的对象
好处:避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类).

当大量从数据源中读取字符串,其中肯定有重复的,那么我们使用Flyweight模式可以提高效率,以唱片CD为例,在一个XML文件中,存放了多个CD的资料.

每个CD有三个字段:
1.出片日期(year)
2.歌唱者姓名等信息(artist)
3.唱片曲目 (title)

其中,歌唱者姓名有可能重复,也就是说,可能有同一个演唱者的多个不同时期
不同曲目的CD.我们将"歌唱者姓名"作为可共享的ConcreteFlyweight.其他两个字段作为UnsharedConcreteFlyweight.

首先看看数据源XML文件的内容:

<?xml version="1.0"?>
<collection>

<cd>
<title>Another Green
World</title>
<year>1978</year>
<artist>Eno,
Brian</artist>
</cd>

<cd>
<title>Greatest
Hits</title>
<year>1950</year>
<artist>Holiday,
Billie</artist>
</cd>

<cd>
<title>Taking Tiger Mountain (by
strategy)</title>
<year>1977</year>
<artist>Eno,
Brian</artist>
</cd>

.......

</collection>

虽然上面举例CD只有3张,CD可看成是大量重复的小类,因为其中成分只有三个字段,而且有重复的(歌唱者姓名).

CD就是类似上面接口 Flyweight:

public class CD {

  private String title;
  private int year;
  private Artist
artist;

  public String getTitle() {  return title; }
  public int getYear()
{    return year;  }
  public Artist getArtist() {    return artist;  }

  public void setTitle(String t){    title = t;}
  public void setYear(int
y){year = y;}
  public void setArtist(Artist a){artist = a;}

}

将"歌唱者姓名"作为可共享的ConcreteFlyweight:

public class Artist {

  //内部状态
  private String name;

  // note that Artist is immutable.
  String getName(){return name;}

  Artist(String n){
    name = n;
  }

}

再看看Flyweight factory,专门用来制造上面的可共享的ConcreteFlyweight:Artist

public class ArtistFactory {

  Hashtable pool = new Hashtable();

  Artist getArtist(String key){

    Artist result;
    result =
(Artist)pool.get(key);
    ////产生新的Artist
    if(result == null)
{
      result = new
Artist(key);
      pool.put(key,result);
      
    }
    return
result;
  }

}

当你有几千张甚至更多CD时,Flyweight模式将节省更多空间,共享的flyweight越多,空间节省也就越大

时间: 2024-08-27 02:16:16

设计模式大类--结构模式(下)的相关文章

设计模式大类--结构模式(上)

大概有7中结构模式,分为上下两篇.一.Adapter(适配器)描述:将两个不兼容的类结合一起使用,一般需要用到其中某个类的若干方法好处:在两个类直接创建一个混合接口,而不必修改类里面的其他代码 例子:假设我们要打桩,有两种类:方形桩 圆形桩.public class SquarePeg{ public void insert(String str){ System.out.println("SquarePeg insert():"+str); } } public class Roun

设计模式大类--行为模式(下)

七.Strategy(策略模式)描述:定义了一系列的算法,将每一种算法封装起来并可以相互替换使用,策略模式让算法独立于使用它的客户应用而独立变化.优点:各个部分之间是弱连接 的关系,弱连接的特性使软件具有更强的可扩展性 ,易于维护 :更重要的是,它大大提高了软件可重用性 . 例子:举例(TreeSet .TreeMap就是很好的例子 )public class Test { /*客户端*/ public static void main(String[] args) { //面向接口 Strat

设计模式大类--行为模式(上)

大概有10中行为模式,分为上中下三篇.一.Template(模板)描述:定义一些操作算法的骨架,将其实现延迟到其子类好处:扩展性强 例子:Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: public abstract class Benchmark{ /** * 下面操作是我们希望在子类中完成 */ public abstract void benchmark(); /** * 重复执行benchmark次数 */ public fina

设计模式大类--行为模式(中)

四.Chain of Responsibility(责任链)描述:一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去好处:降低了类之间的耦合性 例子:抽象处理者角色public abstract class Handler { /** * 持有后继的责任对象*/protecte

php设计模式(二):结构模式

上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式.一.什么是结构型模式? 结构型模式是解析类和对象的内部结构和外部组合,通过优化程序结构解决模块之间的耦合问题. 二.结构型模式的种类:    适配器模式    桥接模式    装饰模式    组合模式    外观模式    享元模式    代理模式 1. 适配器模式(Adapter) 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能

【编程思想】【设计模式】【结构模式Structural】享元模式flyweight

Python版 https://github.com/faif/python-patterns/blob/master/structural/flyweight.py #!/usr/bin/env python # -*- coding: utf-8 -*- """ *References: http://codesnipers.com/?q=python-flyweights *TL;DR80 Minimizes memory usage by sharing data w

【编程思想】【设计模式】【结构模式Structural】门面模式/外观模式Facade

Python版 https://github.com/faif/python-patterns/blob/master/structural/facade.py #!/usr/bin/env python # -*- coding: utf-8 -*- """ *What is this pattern about? The Facade pattern is a way to provide a simpler unified interface to a more com

【编程思想】【设计模式】【结构模式Structural】front_controller

Python版 https://github.com/faif/python-patterns/blob/master/structural/front_controller.py #!/usr/bin/env python # -*- coding: utf-8 -*- """ @author: Gordeev Andrey <[email protected]> *TL;DR80 Provides a centralized entry point that

【编程思想】【设计模式】【结构模式Structural】MVC

Python版 https://github.com/faif/python-patterns/blob/master/structural/mvc.py #!/usr/bin/env python # -*- coding: utf-8 -*- """ *TL;DR80 Separates data in GUIs from the ways it is presented, and accepted. """ class Model(obje