转载请注明来自:http://blog.csdn.net/ndzjx/article/details/78027053
设计模式
-------------结构型模式
目录
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.享元模式(蝇量)
地区:海淀, 人对象
引用计数也是一种例子。