设计模式3.docx
- 文档编号:2407226
- 上传时间:2023-05-03
- 格式:DOCX
- 页数:35
- 大小:129.32KB
设计模式3.docx
《设计模式3.docx》由会员分享,可在线阅读,更多相关《设计模式3.docx(35页珍藏版)》请在冰点文库上搜索。
设计模式3
设计模式学习笔记(十二)——Flyweight享元模式
Flyweight享元设计模式是一种结构型设计模式,它主要解决的问题是:
由于(同类)对象的数量太大,采用面向对象时给系统带来了难以承受的内存开销。
比如有这样一个场景:
一个停车场中有1000辆汽车,我们所定义的汽车对象占用内存0.3M,那么要实例化1000辆就是300M。
由此可见,在这种情况下采用一般的面向对象方式出现了大量细粒度的对象会很快充斥在系统中,从而带来很高的运行是代价(这里指的代价是内存开销的代价)。
GoF《设计模式》中说道:
运用共享技术有效的支持大量细粒度的对象。
Flyweight模式的结构大概是这样的:
(这张图是按照我的理解画出来的,如果有不对的地方还请帮我指正,谢谢),从图上可以看出Flyweight模式是将相同的对象存为一个,就是在FlyweightFactory中对于实例化对象的判断。
这样,客户代码即使是调用1000000个对象,如果这些对象的种类只有一个的话,对于内存的分配上也只是分配了一个对象的空间。
但是有一点我想要注意:
就是对于引用对象来说,这样做,如果其中某一个对象发生变化,那么同类中的所有对象也会随之变化。
来看看程序,定义一个场景:
有一个汽车类型,客户程序要实例化1000个,实例化后查看一下内存分配情况。
普通的面向对象方式:
classClass1
{
[STAThread]
staticvoidMain(string[]args)
{
Console.WriteLine("实例化前:
"+GC.GetTotalMemory(false));
ArrayListlist=newArrayList(1000);
for(inti=0;i<1000;i++)
{
Carcar=newCar("4.2M","Wheel","NeedForSpeed","BMW","Black");
list.Add(car);
}
Console.WriteLine("实例化后:
"+GC.GetTotalMemory(false));
Console.Read();
}
}
publicclassCar
{
privatestringbody;
privatestringwheel;
privatestringengine;
privatestringbrand;
privatestringcolor;
publicstringBody
{
get{returnbody;}
set{body=value;}
}
publicstringWheel
{
get{returnwheel;}
set{wheel=value;}
}
publicstringEngine
{
get{returnengine;}
set{engine=value;}
}
publicstringBrand
{
get{returnbrand;}
set{brand=value;}
}
publicstringColor
{
get{returncolor;}
set{color=value;}
}
publicCar(stringbody,stringwheel,stringengine,stringbrand,stringcolor)
{
Body=body;
Wheel=wheel;
Engine=engine;
Brand=brand;
Color=color;
}
}
内存分配情况如下:
实例化前:
16384
实例化后:
65536
然后再用Flyweight模式方式程序做一下比较:
classClass1
{
[STAThread]
staticvoidMain(string[]args)
{
Console.WriteLine("实例化前:
"+GC.GetTotalMemory(false));
ArrayListlist=newArrayList(1000);
for(inti=0;i<1000;i++)
{
FlyWeightCarcar=FlyWeightFactory.CreateInit("4.2M","Wheel","NeedForSpeed","BMW","Black");
list.Add(car);
}
Console.WriteLine("实例化后:
"+GC.GetTotalMemory(false));
Console.Read();
}
}
publicclassFlyWeightFactory
{
privatestaticFlyWeightCarcar;
privatestaticHashtabletable=newHashtable();
publicstaticFlyWeightCarCreateInit(stringbody,stringwheel,stringengine,stringbrand,stringcolor)
{
if(table[brand]!
=null)
{
car=(FlyWeightCar)table[brand];
}
else
{
car=newFlyWeightCar();
car.Brand=brand;
car.CarBody=newCarBody(body,wheel,engine,color);
table.Add(brand,car);
}
returncar;
}
}
publicclassFlyWeightCar
{
privatestringbrand;
publicstringBrand
{
get
{
returnbrand;
}
set
{
brand=value;
}
}
privateCarBodycarbody;
publicCarBodyCarBody
{
get
{
returncarbody;
}
set
{
this.carbody=value;
}
}
}
publicclassCarBody
{
privatestringbody;
privatestringwheel;
privatestringengine;
privatestringcolor;
publicstringBody
{
get{returnbody;}
set{body=value;}
}
publicstringWheel
{
get{returnwheel;}
set{wheel=value;}
}
publicstringEngine
{
get{returnengine;}
set{engine=value;}
}
publicstringColor
{
get{returncolor;}
set{color=value;}
}
publicCarBody(stringbody,stringwheel,stringengine,stringcolor)
{
Body=body;
Wheel=wheel;
Engine=engine;
Color=color;
}
}
内存分配情况:
实例化前:
16384
实例化后:
40960
从数字上不难看出内存分配的容量节省了不少,而且随着数量的增加,差距会更大,当然我也测试了一下数量减少的情况,当我实例化100个对象是结果是普通方式的内存分配更小一些,所以,在使用时,我们一定要对所实例化对象的个数进行评估,否则的话会适得其反。
Flyweight模式的几个要点:
1、面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。
Flyweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。
2、Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。
在具体实现方面,要注意对象的状态处理。
3、对象的数量太大从而导致对象内存开销加大(这个数量要经过评估,而不能凭空臆断)
设计模式学习笔记(十三)——Proxy代理模式
Proxy代理模式是一种结构型设计模式,主要解决的问题是:
在直接访问对象时带来的问题,比如说:
要访问的对象在远程的机器上。
在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
如下图:
比如说C和A不在一个服务器上,A要频繁的调用C,我们可以在A上做一个代理类Proxy,把访问C的工作交给Proxy,这样对于A来说,就好像在直接访问C的对象。
在对A的开发中我们可以把注意力完全放在业务的实现上。
GoF《设计模式》中说道:
为其他对象提供一种代理以控制这个对象的访问。
Proxy模式的结构:
下面通过一个场景来看看Proxy的实现,我们要使用代理类型ProxyClass的对象调用远程机器上的一个类型LongDistanceClass的对象。
首先我们先模拟一个远程的类型:
为了保持对被代理对象使用的透明性,我们使代理类型和被代理类型同时继承同一个接口IProxy
接口实现:
interfaceIProxy
{
stringFunction1();
stringFunction2();
}
远程对象实现:
///
///模拟的远程对象
///
publicclassLongDistanceClass:
IProxy
{
#regionIProxy成员
publicstringFunction1()
{
//dosometing
return"LongDistanceClass.Function1";
}
publicstringFunction2()
{
//dosometing
return"LongDistanceClass.Function2";
}
#endregion
}
接下来就要实现代理类型,使用代理对象访问模拟的远程对象,代理类型实现如下:
publicclassProxyClass:
IProxy
{
#regionIProxy成员
publicstringFunction1()
{
//toaccessLongDistanceClass.Function1
LongDistanceClassobj=newLongDistanceClass();
returnobj.Function1();
}
publicstringFunction2()
{
//toaccessLongDistanceClass.Function2
LongDistanceClassobj=newLongDistanceClass();
returnobj.Function2();
}
#endregion
}
最后实现客户端代码:
classClass1
{
[STAThread]
staticvoidMain(string[]args)
{
IProxypro=newProxyClass();
Console.WriteLine(pro.Function1());
Console.WriteLine(pro.Function2());
Console.Read();
}
}
运行结果如下:
LongDistanceClass.Function1
LongDistanceClass.Function2
Proxy模式的要点:
1、“增加一层间接层”是软件系统中对许多负责问题的一种常见解决方法。
在面向对象系统中,直接使用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常用手段。
在我们日常的工作中也常常用到代理模式,比如对于三层结构或者N-tiers结构中DAL数据访问层,它把对数据库的访问进行封装。
BLL业务层的开发者只是调用DAL中的方法来获得数据。
在比如前一段时间看了看AOP和Remoting方面的资料,对于跨越应用程序域的访问,要为客户应用程序提供一个TransparentProxy(透明代理),客户程序实际上是通过访问这个代理来访问实际的类型对象。
2、具体proxy设计模式的实现方法、实现粒度都相差很大,有些可能对单个对象作细粒度的控制,有些可能对组件模块提供抽象代理层,在架构层次对对象作proxy。
3、proxy并不一定要求保持接口的一致性,只要能够实现间接控制,有时候损及一些透明性是可以接受的。
例如上面的那个例子,代理类型ProxyClass和被代理类型LongDistanceClass可以不用继承自同一个接口,正像GoF《设计模式》中说的:
为其他对象提供一种代理以控制这个对象的访问。
代理类型从某种角度上讲也可以起到控制被代理类型的访问的作用。
设计模式学习笔记(十四)——创建型模式总结
GoF23种设计模式中创建型模式有5种,分别是:
Singleton单件模式、AbstractFactory抽象工厂模式、Builder生成器模式、FactoryMethod工厂方法模式、Prototype原形模式。
下面分别总结这几种设计模式。
设计模式
GoF的描述
我的理解
Singleton单件模式
保证一个类仅有一个实例,并提供一个该实例全局的访问点
控制实体对象的数量
AbstractFactory抽象工厂模式
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们的具体类
解决一个系列的对象变化的问题
Builder生成器模式
将一个复杂对象的构建与其表示向分离,使得同样的构建过程可以创建不同的表示
应对项目中一些复杂对象的创建工作。
所谓“复杂对象”,是指:
此对象中还含有其它的子对象
FactoryMethod工厂方法模式
定义一个用于创建对象的接口,让子类决定实例化那个类。
FactoryMethod使得一个类的实例化延迟到子类
解决的是“某个对象”的创建工作,由于需求的变化,这个对象常常面临着剧烈的变化,但是这个对象拥有的接口相对稳定。
也就是说:
枝节常常发生变化,但是枝节与主干的接口相对稳定
Prototype原形模式
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象
某些结构复杂的对象的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口
在学习的过程中,觉得从功能上看AbstractFactory模式和Builder模式容易混淆,FactoryMethod模式和Prototype模式不好区分。
Singleton模式没什么太大的困难。
下面就来分析一下前四种模式。
一、AbstractFactory模式和Builder模式:
AbstractFactory是应对一系列对象的创建的问题,正如前面文章中举的例子,对于创建一个汽车对象来说,AbstractFactory模式更关注一系列的对象的创建,或者说是汽车类型中的各个部分,如:
Wheel、Engine、Body等等类型的创建。
换句话说关注点在这一系列对象上。
Builder是应对一个复杂对象创建的问题,或者说是针对这个复杂对象中的子对象的创建的问题。
以汽车的例子来说,我觉得比起AbstractFactory模式,Builder模式相对注重汽车类型(上面所说的“复杂对象”)本身以及其各个部分(Wheel、Engine、Body等等)类型的创建。
Builder模式要求这个复杂的类型(汽车)中的各个子类型的结合部分相对稳定,用例子说明就是对于汽车来说,无论用什么配件组装,个个配件的组装方式都一样,有相对稳定的接口。
对于这辆车你用什么牌子的Wheel、什么牌子的Engine可能变化会很大很频繁。
二、FactoryMethod模式和Prototype模式:
开始我觉得这两种模式从功能上讲是一样的(个人观点),都是封装了对对象的创建,只不过Prototype模式是用原型克隆进行拷贝来完成对象的创建,在这之中还应注意浅拷贝和深拷贝的区别。
在向同事请教后有点明白。
这两种模式在应用场景上还是一定的区别的。
FactoryMethod模式是重新创建一个对象
Prototype模式是利用现有的对象进行克隆,当两个对象或多个对象雷同的时候,可以考虑用一个已创建的对象去克隆出其余的对象。
以上是对创建型模式的总结,如有不对的观点欢迎指正。
设计模式学习笔记(十五)——结构型模式总结
结构型设计模式是从程序的结构上解决模块之间的耦合问题(好像是句废话),GoF23种设计模式中结构型设计模式有7种,分别是:
Adapter适配器模式、Bridge桥接模式、Composite组合模式、Decorator装饰模式、Facade外观模式、Flyweight享元模式和Proxy代理模式。
下面分别总结一下这几种模式:
设计模式
GoF的描述
我的理解
Adapter适配器模式
将一个类的接口转换成客户希望的另一个接口。
Adapter模式使得原本由于接口不兼容而不能一起工作的类可以一起工作
转换接口,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是,新环境要求的接口是现存对象所不满足的,此时我们可以通过添加一层Adapter对现有的对象加入一些接口,使其适应新的应用环境。
Bridge桥接模式
将抽象部分与实现部分分离,使他们可以独立的变化
分离接口(抽象)与其实现,当某个类型具有两个或两个以上的纬度变化(或者说是变化点),通过以继承接口的方式隔离变化,以减少因变化带来的代码的修改量。
Composite组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构。
Composite模式使得客户对单个对象和组合对象的使用具有一致性
解决客户程序与复杂对象容器的解耦,一类具有“容器特征”的对象——即他们在充当对象的同时,又是其他对象的容器的情况,通过继承统一的接口,我们可以将容器对象及其子对象看成同一类对象使用,以减少对象使用中的复杂度。
Decorator装饰模式
动态的给一个对象添加一些额外的职责。
就增加功能而言,Decorator模式比生成子类更为灵活
在稳定接口的前提下为对象扩展功能,主要是解决用继承的方式为对象扩展大量功能而造成的子对象数量膨胀的问题
Facade外观模式
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
简化接口,对于复杂子系统或子对象调用的封装。
从客户程序角度看,只能看见Facade提供的接口。
换句话说是对子对象调用的封装,将客户程序对子对象的调用与子对象的变化分离。
Flyweight享元模式
运用共享技术有效的支持大量细粒度的对象
主要是解决由于相同对象数量过大而造成系统内存开销过大的问题。
实际上是相同的对象引用指向同一个对象空间。
在使用Flyweight模式前要做一个评估,如果使用不当会适得其反
Proxy代理模式
为其他对象提供一种代理以控制这个对象的访问
解决直接访问某些对象是出现的问题,如:
访问远程的对象
在学习的过程中感觉,从代码的角度看Adapter适配器模式和Proxy代理模式有些类似,Adapter适配器模式是解决现有对象在新的环境中的不足,而Proxy代理模式是解决直接访问对象时出现的问题,这两种模式从使用角度看都是解决直接访问对象时出现的问题,只是含义不十分相同。
设计模式学习笔记(十六)——TemplateMethod模板方法模式
今天开始学习设计模式中的第三个类型——行为型模式。
行为模式:
行为型模式涉及到算法和对象间职责的分配。
将注意力从控制流转移到对象间的联系方式上来。
行为模式分为:
行为类模式和行为对象模式。
行为类模式使用继承机制在类间分派行为;行为对象模式使用对象复合而不是继承。
TemplateMethod模板方法模式
TemplateMethod模板方法模式介绍:
TemplateMethod模板方法模式是一种行为型模式,具体点说是行为类型模式。
主要解决在软件构建过程中,对于某一项任务,常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因而无法和任务的整体结构同时实现。
GoF《设计模式》中说道:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
TemplateMethod模式的结构
定义场景
单看结构不好理解,我们来结合程序进行分析。
现在定义一个场景:
我想大家都玩过极品飞车(我相当喜欢)。
游戏中有很多的汽车,但是从操作角度看大同小异。
无非是起步(StartUp)、行驶(Run)、停车(Stop)等等行为。
汽车行驶的动作之间可能存在着差异,例如:
手动档和自动档,但是接口是一样的,换句话说,基本都是这几个动作。
结合TemplateMethod模式讲就是在这个程序中,结构(对汽车的操作)是稳定的,但是变化在于各个子步骤(操作行为的具体实现)。
程序实现与结构分析
首先我们需要一个汽车的抽象类(结构图中的AbstractClass)
publicabstractclassAbstractCar
{
protectedabstractstringStartUp();
protectedabstractstringRun();
protectedabstractstringStop();
publicvoidDrive
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 设计 模式
![提示](https://static.bingdoc.com/images/bang_tan.gif)