设计模式----结构型模式


转载请注明来自:http://blog.csdn.net/ndzjx/article/details/78027053

设计模式

-------------结构型模式

目录

设计模式

1.适配器模式

2.装饰者模式

3.组合模式

4.外观模式

5.桥接模式

6.代理模式

7.享元模式

 

 

 

1.适配器模式

将一个类的接口,转换成客户期望的另一个接口。让原本不兼容的类,可以合作无间。

 

 

鸭子:

public interface Duck {
    publicvoid quack();
    publicvoid fly();
}
 
public class MallardDuck implements Duck {
    publicvoid quack() {
           System.out.println("Quack");
    }
 
    publicvoid fly() {
           System.out.println("I'mflying");
    }
}



火鸡:

public interface Turkey {
    publicvoid gobble();
    publicvoid fly();
}
 
public class WildTurkey implements Turkey {
    publicvoid gobble() {
           System.out.println("Gobblegobble");
    }
 
    publicvoid fly() {
           System.out.println("I'mflying a short distance");
    }
}



火鸡冒充鸭子:

public class TurkeyAdapter implements Duck{
    Turkeyturkey; // 组合一个火鸡
 
    publicTurkeyAdapter(Turkey turkey) {
           this.turkey= turkey;
    }
 
    publicvoid quack() {
           turkey.gobble();
    }
 
    publicvoid fly() {
           for(int i = 0; i < 5; i++) {
                  turkey.fly();
           }
    }
}


类图:

1.对象适配器:采用组合方式

 

 

例子:代码中的Adaptor

 

2.类适配器:采用多重继承的方式

 

class Adaptor : publicWildTurkey(类), Duck(接口)

火鸡类没有鸭子的方法,适配器可以将对鸭子方法的调用,转接到调用火鸡方法。

 

 

 

区别:

       类适配器:

1.     采用多重继承

2.     可以覆盖被适配者的行为,因为采用的是继承的方式

 

对象适配器:

1.     采用组合

2.     不仅可以适配某个类,也可以适配该类的任何子类

 

 

(一个继承,一个组合,工厂方法与抽象工厂也是这样的关系)

 

so.将一个类的接口,转换成客户期望的另一个接口。让原本不兼容的类,可以合作无间。

 

2.装饰者模式

       动态地将责任附加到对象上。若要扩展功能,装饰者提供比继承更有弹性的替代方案。(对扩展开放,对修改封闭)

 

饮料接口:

public abstract class Beverage {
       protectedString description = "Unknown Beverage";
 
       publicString getDescription() {
              returndescription;
       }
 
       publicabstract double cost();
}


浓咖啡:

public class Espresso extends Beverage {
 
       publicEspresso() {
              description= "Espresso";
       }
 
       publicdouble cost() {
              return1.99;
       }
}

装饰器接口:

public abstract class CondimentDecorator extends Beverage {
	public abstract String getDescription();
}

摩卡咖啡:

public class Mocha extends CondimentDecorator {
	Beverage beverage;

	public Mocha(Beverage beverage) {
		this.beverage = beverage;
	}

	public String getDescription() {
		return beverage.getDescription() + ", Mocha";
	}

	public double cost() {
		return .20 + beverage.cost();
	}
}


主函数:

public class StarbuzzCoffee {
 
       publicstatic void main(String[] args) {
              Beveragebeverage = new Espresso();
              System.out.println(beverage.getDescription()+ " $" + beverage.cost());
 
              Beveragebeverage2 = new Espresso ();
              beverage2= new Mocha(beverage2);
              beverage2= new Whip(beverage2);
              System.out.println(beverage2.getDescription()+ " $" + beverage2.cost());
       }
}

类图:试想装饰可以无限的装饰下去

 

 

 

1:对于某些客户,会不会容易不使用最外层的装饰者呢?

       答:我们有工厂和生成器模式 可以搞定这件事。

 

 

缺点:装饰者会导致设计中出现许多小对象,过度使用,会让程序变得很复杂。

 

 

装饰者相对于适配器:

 

装饰者:扩展对象的行为或责任,加入新的行为或责任。

适配器:对接口进行转换

 

so. 动态地将责任附加到对象上。若要扩展功能,装饰者提供比继承更有弹性的替代方案。(对扩展开放,对修改封闭)

 

3.组合模式

       允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

 

比如:

 

菜单接口:

public abstractclass MenuComponent {
  
       public void add(MenuComponentmenuComponent) {
              throw newUnsupportedOperationException();
       }
       public void remove(MenuComponentmenuComponent) {
              throw newUnsupportedOperationException();
       }
       public MenuComponent getChild(int i) {
              throw new UnsupportedOperationException();
       }
 
       public String getName() {
              throw newUnsupportedOperationException();
       }
       public String getDescription() {
              throw newUnsupportedOperationException();
       }
       public double getPrice() {
              throw new UnsupportedOperationException();
       }
       public boolean isVegetarian() {
              throw newUnsupportedOperationException();
       }
 
       public void print() {
              throw newUnsupportedOperationException();
       }
}


 

 

菜单项:

public classMenuItem extends MenuComponent {
       String name;
       String description;
       boolean vegetarian;
       double price;
 
       public MenuItem(String name, Stringdescription, boolean vegetarian,
                     double price) {
              this.name = name;
              this.description = description;
              this.vegetarian = vegetarian;
              this.price = price;
       }
       。。。。。。。。。
}


 

菜单:

public class Menuextends MenuComponent {
       ArrayList<MenuComponent>menuComponents = new ArrayList<MenuComponent>();
       String name;
       String description;
 
       public Menu(String name, Stringdescription) {
              this.name = name;
              this.description = description;
       }
 
       public void add(MenuComponentmenuComponent) {
              menuComponents.add(menuComponent);
       }
 
       public void remove(MenuComponentmenuComponent) {
              menuComponents.remove(menuComponent);
       }
 
       public MenuComponent getChild(int i) {
              return (MenuComponent)menuComponents.get(i);
       }
 
       public String getName() {
              return name;
       }
 
       public String getDescription() {
              return description;
       }
 
       public void print() {
              System.out.print("\n" +getName());
              System.out.println(", "+ getDescription());
              System.out.println("---------------------");
 
              Iterator<MenuComponent>iterator = menuComponents.iterator();
              while (iterator.hasNext()) {
                     MenuComponent menuComponent= iterator.next();
                     menuComponent.print();
              }
       }
}


测试:

public classMenuTestDrive {
       public static void main(String args[]) {
              MenuComponent pancakeHouseMenu =new Menu("PANCAKE HOUSE MENU","Breakfast");
              MenuComponent dinerMenu = newMenu("DINER MENU", "Lunch");
             
              pancakeHouseMenu.add(newMenuItem("K&B's Pancake Breakfast",
                            "Pancakes withscrambled eggs, and toast", true, 2.99));
              pancakeHouseMenu.add(dinerMenu);
。。。。。。。。
}
}


类图:


 

 

类图与装饰者有点相似:都是组合,不过组合模式表现的是整体与部分的关系,组合的大都是一个列表。

而装饰者模式主要的意图是,增加额外的行为或指责,一般是装饰一个对象。

 

 

so. 允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

 

 

 

4.外观模式

       facade [fə'sɑːd]提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

       迪米特法则:最少知道原则

 

 

比如,你想看电影,必须先执行一些任务:

 

 

 

当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。

 





类图:

 

 

适配器:包装一个对象(可以是许多对象)改变其接口,转换成不同接口

装饰者:包装对象,增加新的行为和责任

外观:包装一群对象来简化接口

       外观没有“封装”子系统,只是提供简化的接口,提供接口的同时,依然将系统完整的功能暴露出来。

       一个子系统可以有许多个外观。

       三者的意图是不一样的。

 

so. facade [fə'sɑːd]提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

 

 

 

5.桥接模式

       不只改变你的实现,也改变你的抽象。抽象和实现在两个不同的类层次中。

 

09年下半年试题:

现欲实现一个图像浏览系统,要求该系统能够显示BMP、3PEG和GIF三种格式的文件,并且能够在Windows和Linux两种操作系统上运行。系统首先将BMP、JPEG和 GIF三种格式的文件解析为像素矩阵,然后将像素矩阵显示在屏幕上。系统需具有较好的扩展性以支持新的文件格式和操作系统。为满足上述需求并减少所需生成的子类数目,采用桥接(Bridge)设计模式进行设计,所得类图如下图所示。

   

    采用该设计模式的原因在于:系统解析BMP、GIF与JPEG文件的代码仅与文件格式相关,而在屏幕上显示像素矩阵的代码则仅与操作系统相关。

[C++代码]

    
classMatrix{    //各种格式的文件最终都被转化为像素矩阵
    //此处代码省略
};
 
classImageImp{
public:
    virtualvoiddoPaint(Matrixm)=0;  //显示像素矩阵m
};
 
classWinImp:publicImageImp
{
public:
    voiddoPaint(Matrixm){/*调用Windows系统的绘制函数绘制像素矩阵*/}
};
 
classLinuxImp:publicImageImp{
public:
    voiddoPaint(Matrixm){/*调用Linux系统的绘制函数绘制像素矩阵*/}
};
 
classImage{
public:
    voidsetImp(ImageImp*imp){this->imp=imp;}
    virtualvoidparseFile(stringfileName)=0;
protected:
    ImageImp*imp;
};
 
class  BMP:publicImage{
public:
    voidparseFile(stringfileName){
       //此处解析BMP文件并获得一个像素矩阵对象m
       imp->doPaint(m);//显示像素矩阵m
    }
};
 
class  GIF:publicImage{
    //此处代码省略
};
 
class  JPEG:publicImage{
    //此处代码省略
};
 
voidmain(){
    //在Windows操作系统上查看demo.bmp图像文件
    Image*imagel=newBMP;
    ImageImp*imageImpl=newWinImp;
    imagel->setImp(imageImpl);
    imagel->parseFile("demo.bmp");
}

 

    现假设该系统需要支持10种格式的图像文件和5种操作系统,不考虑类Matrix,若采用桥接设计模式则至少需要设计 17个类。

 

 


类图:

 

so. 不只改变你的实现,也改变你的抽象。抽象和实现在两个不同的类层次中。

 

6.代理模式

       为另一个对象提供一个替身或占位符以控制对这个对象的访问。

根据职责不同,代理分为:

远程代理:控制访问远程对象

虚拟代理:控制访问开销大的对象(图片加载,完全创建之前提供屏幕上的代表)

保护代理:基于权限控制对资源的访问

等。。。。

 

类图:

 

       适配器是改变对象适配的接口,而代理是实现相同的接口。

       保护代理只提供客户部分接口,就跟适配器很像了。

       要让客户只使用代理,不使用真正的对象,我们有工厂。

 

       装饰者只能装饰点缀,从来不实例化东西。而代理会,比如虚拟代理(图片加载)

       例子

7.享元模式(蝇量)

         地区:海淀, 人对象

        


例子

 

引用计数也是一种例子。

 






 

猜你喜欢

转载自blog.csdn.net/ndzjx/article/details/78027053