• C#设计模式——享元模式(Flyweight Pattern)


    C#设计模式——享元模式(Flyweight Pattern)

    一、概述

    在软件开发中,我们有时需要创建大量细粒度的对象,比如文档处理系统就可能需要创建成千上万的字符对象。但如果对每个字符对象都分配内存,那么在系统运行时就会耗费大量的内存。如何在保留面向对象操作方式优点的同时避免创建大量的对象呢?这就到了享元模式发挥作用的时候了。

    二、享元模式

    享元模式运用共享技术有效地支持大量细粒度的对象。例如可以对文档处理系统创建共享池,在共享池中建立字母和代码的对应关系,这样就可以用共享池中的26个对象解决需要创建大量对象的问题。其结构图如下:

    Flyweight定义了享元接口,外部对象通过这个接口来访问具体的享元对象。

    ConcreteFlyweight实现Flyweight接口,定义了具体的享元对象,并保存享元对象的内部状态。该享元对象是可共享的。

    UnsharedConcreteFlyweight实现Flyweight接口,定义了不用于共享的享元对象。

    FlyweightFactory创建并管理享元对象。

    Client保存对享元接口的引用,通过该引用有效的使用具体的享元对象。

    三、示例

    我们简单的实现本文开头所表述的文档处理系统。

    首先定义Flyweight。

    复制代码
     1     public abstract class Character
     2     {
     3         public int Size { get; set; }
     4         public Color Color { get; set; }
     5         protected char _c;
     6 
     7         public Character()
     8         {
     9             Size = 10;
    10             Color = Color.Black;
    11         }
    12 
    13         public override string ToString()
    14         {
    15             return string.Format("Character is {0}, Size is {1}, Color is {2}", _c, Size.ToString(), Color.ToString());
    16         }
    17     }
    复制代码

    然后实现具体的享元对象。

    复制代码
     1     public class CharacterA : Character
     2     {
     3         public CharacterA()
     4         {
     5             _c = 'A';
     6         }
     7     }
     8 
     9     public class CharacterB : Character
    10     {
    11         public CharacterB()
    12         {
    13             _c = 'B';
    14         }
    15     }
    16 
    17     public class CharacterC : Character
    18     {
    19         public CharacterC()
    20         {
    21             _c = 'C';
    22         }
    23     }
    复制代码

    接着定义FlyweightFactory并建立共享池。

    复制代码
     1     public static class CharacterFactory
     2     {
     3         private static Dictionary<char, Character> _characters;
     4 
     5         static CharacterFactory()
     6         {
     7             _characters = new Dictionary<char, Character>();
     8             _characters.Add('a', new CharacterA());
     9             _characters.Add('b', new CharacterB());
    10             _characters.Add('c', new CharacterC());
    11         }
    12 
    13         public static Character GetCharacter(char c)
    14         {
    15             return _characters[c];
    16         }
    17     }
    复制代码

    最后看一下如何使用这些享元对象。

    复制代码
     1     static void Main(string[] args)
     2     {
     3         Character character = CharacterFactory.GetCharacter('a');
     4         Console.WriteLine(character.ToString());
     5         character = CharacterFactory.GetCharacter('b');
     6         character.Size = 20;
     7         character.Color = Color.Red;
     8         Console.WriteLine(character.ToString());
     9         character = CharacterFactory.GetCharacter('c');
    10         character.Size = 15;
    11         character.Color = Color.Yellow;
    12         Console.WriteLine(character.ToString());
    13     }
    复制代码
     
     
    分类: 设计模式

    设计模式

     
    摘要: 一、概述在软件开发中,我们有时需要创建大量细粒度的对象,比如文档处理系统就可能需要创建成千上万的字符对象。但如果对每个字符对象都分配内存,那么在系统运行时就会耗费大量的内存。如何在保留面向对象操作方式优点的同时避免创建大量的对象呢?这就到了享元模式发挥作用的时候了。二、享元模式享元模式运用共享技术有效地支持大量细粒度的对象。例如可以对文档处理系统创建共享池,在共享池中建立字母和代码的对应关系,这样就可以用共享池中的26个对象解决需要创建大量对象的问题。其结构图如下:Flyweight定义了享元接口,外部对象通过这个接口来访问具体的享元对象。ConcreteFlyweight实现Flyweigh阅读全文
    posted @ 2013-02-18 22:17 saville 阅读(847) | 评论 (1) 编辑

    摘要: 一、概述在软件开发中,经常会碰上某些对象,其创建的过程比较复杂,而且随着需求的变化,其创建过程也会发生剧烈的变化,但他们的接口却能比较稳定。对这类对象的创建,我们应该遵循依赖倒置原则,即抽象不应该依赖于实现细节,实现细节应该依赖于抽象。原型模式为我们提供了这样一个解决方案,使得客户程序可以隔离出这些易变的创建过程,从而摆脱创建细节的纠缠。二、原型模式原型模式可以用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。其结构图如下:Prototype声明了克隆自身的一个接口。ConcretePrototype继承Prototype并定义了克隆自身的操作。Client通过原先克隆自身来创建阅读全文
    posted @ 2013-01-10 22:21 saville 阅读(581) | 评论 (0) 编辑

    摘要: 一、概述在软件开发中,我们有时候会遇上一个对象具有多个变化维度。比如对汽车对象来说,可能存在不同的汽车类型,如公共汽车、轿车等,也可能存在不同的发动机,如汽油发动机、柴油发动机等。对这类对象,可应用桥接模式来增强系统灵活度,避免由于多维度变化带来的复杂性。二、桥接模式桥接模式利用对象的组合关系将不同的变化维度分离,使其可以沿着各自的维度来变化。其结构图如下:Abstraction定义了抽象类,并包含Implementor对象。RefinedAbstraction实现了抽象类。Implementor定义了另一个变化维度。ConcreteImplementor提供了第二个变化维度接口的具体实现。三阅读全文
    posted @ 2012-12-05 18:40 saville 阅读(74) | 评论 (0) 编辑

    摘要: 一、概述在软件开发中,我们往往会遇上类似树形结构的对象体系。即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在。比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点。在设计这类对象时,如果将叶节点和分支节点区别对待,那么在实际开发中会带来较大的复杂性。比如客户端调用时可能会频繁的使用转型操作,同时代码的可维护性和扩展性也较差。在设计中使用组合模式可以解决这一系列弊端。二、组合模式组合模式定义了叶节点和分支节点的一致的接口,将客户端代码与复杂的对象结构解耦,大大降低了客户端调用的复杂性。其结构图如下:Component定义了所有对象的共同接口,可以在Component中定阅读全文
    posted @ 2012-11-11 22:48 saville 阅读(918) | 评论 (3) 编辑

    摘要: 一、概述在系统设计中,某一个系统可能非常庞大,用户要使用该系统就不得不掌握大量的接口,造成使用的不便。这时可以考虑将该系统细分成一系列子系统并使子系统间的耦合降到最低,利用外观模式提供一个外观对象,为这一系列子系统提供一个简单的使用接口,这样用户只需要掌握外观对象上的少量接口即可使用该系统。就以汽车为例,一辆汽车由引擎、车轮、刹车等无数子系统构成,大多数用户在实际使用过程中并不关心这些子系统之间的工作细节,他们只希望能简单的启动、刹车即可。二、外观模式外观模式为系统中的一组接口定义了一个高层接口,这个接口使得这一系统更加容易使用。外观模式能有效简化外部程序和系统间的交互接口,将外部程序的演化和阅读全文
    posted @ 2012-10-18 20:33 saville 阅读(65) | 评论 (0) 编辑

    摘要: 一、概述在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使用职责链模式,职责链模式可以向多个处理对象提交请求,具体由哪个处理对象进行处理则是在运行过程中动态指定。二、职责链模式职责链模式将多个处理对象连接形成一条链,并沿着该链传递需处理的请求,直到有一个对象被处理或是请求被传递到链的末尾为止。该模式将请求与处理解耦,可以动态的增减处理职责,增加了灵活性。其结构图如下:Handler定义了处理对象的接口,往往通过它来实现后继的职责链。ConcreteHand阅读全文
    posted @ 2012-09-04 20:58 saville 阅读(276) | 评论 (0) 编辑

    摘要: 一、概述在软件设计工作中会存在对象之间的依赖关系,当某一对象发生变化时,所有依赖它的对象都需要得到通知。如果设计的不好,很容易造成对象之间的耦合度太高,难以应对变化。使用观察者模式可以降低对象之间的依赖,以松耦合的方式实现这一目标。二、观察者模式观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。其结构图如下:Subject知道它的所有观察者并提供了观察者注册和删除订阅的接口。Observer为那些在目标发生改变时需获得通知的对象定义一个更新接口。ConcreteSubject实现Subject接口,当改变状态时向依赖于它的Concr阅读全文
    posted @ 2012-08-15 16:33 saville 阅读(233) | 评论 (0) 编辑

    摘要: 一、概述由于需求的改变,某些类常常需要增加新的功能,但由于种种原因这些类层次必须保持稳定,不允许开发人员随意修改。对此,访问者模式可以在不更改类层次结构的前提下透明的为各个类动态添加新的功能。二、访问者模式访问者模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。其结构图如下:Visitor为每一个ConcreteElement声明一个Visitor操作。ConcreteVisitor实现了Visitor声明的操作,其定义的行为就是需要动态添加到ConcreteElement中的新功能。Element定义一个以Visitor为参数的Ac阅读全文
    posted @ 2012-07-10 12:19 saville 阅读(187) | 评论 (0) 编辑

    摘要: 一、概述在软件系统中,有时候面临着复杂的对象创建,该对象由一定算法构成的子对象组成,由于需求变化,这些子对象会经常变换,但组合在一起的算法却是稳定的。生成器模式可以处理这类对象的构建,它提供了一种封装机制来隔离各类子对象的变化,从而保证系统的稳定。二、生成器模式生成器模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。其结构图如下:Builder为创建Product对象的各个子对象指定抽象接口。ConcreteBuilder实现了Builder接口,用于创建Product对象的各个子对象。Director使用Builder来创建Product对象。Product表示被阅读全文
    posted @ 2012-06-13 10:50 saville 阅读(1268) | 评论 (2) 编辑

    摘要: 一、概述在软件开发中,有些对象由于创建成本高、访问时需要与其它进程交互等原因,直接访问会造成系统速度慢、复杂度增大等问题。这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系统复杂性、提高系统性能的目的。二、代理模式代理模式为其他对象提供一种代理以控制对这个对象的访问。其结构图如下:Subject定义了RealSubject和Proxy共用的接口,使得在任何使用RealSubject的地方都可以使用ProxyRealSubject定义了Proxy所代表的实体。Proxy定义了一个控制RealSubject的代理,供Client使用。代理模式根据用途不同可以分为几种类型阅读全文
    posted @ 2012-05-23 16:16 saville 阅读(768) | 评论 (0) 编辑

    摘要: 一、概述在软件开发中,常常会想要复用一个已经存在的组件,但该组件的接口却与我们的需要不相符,这时我们可以创建一个适配器,在需复用的组件的接口和我们需要的接口间进行转换,从而能够正常的使用需复用的组件。这就是适配器模式。二、适配器模式适配器模式将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式可分为类适配器和对象适配器两种,类适配器使用多重继承对两个接口进行匹配,对象适配器则依赖于对象的组合。类适配器模式的结构图如下:对象适配器模式的结构图如下:Target定义了客户需要使用的接口。Adaptee定义了已经存在的那个接口,该接口需要通过阅读全文
    posted @ 2012-04-12 15:04 saville 阅读(1023) | 评论 (5) 编辑

    摘要: 一、概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就可以用到工厂方法模式了。二、工厂方法模式工厂方法模式定义了一个用于创建对象的接口,让其子类决定实例化哪一个对象。使一个对象的创建工作延迟到其子类。工厂方法模式的结构图如下:Product定义了工厂方法所创建的对象的接口。ConcreteProduct实现Product接口, 定义了具体对象。Creator定义了具体对象创建阅读全文
    posted @ 2012-03-15 15:54 saville 阅读(897) | 评论 (0) 编辑

    摘要: 一、概述在软件开发中,常常会需要创建一系列相互依赖的对象,同时,由于需求的变化,往往存在较多系列对象的创建工作。如果采用常规的创建方法(new),会造成客户程序和对象创建工作的紧耦合。对此,抽象工厂模式提供了一种解耦手段。二、抽象工厂模式抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式的结构图如下:AbstractFactory声明了一个创建抽象产品对象的操作接口。ConcreteFactory实现了创建具体产品对象的操作。AbstractProduct为一类产品对象声明一个接口。ConcreteProduct实现AbstractProduct接口,阅读全文
    posted @ 2012-02-07 16:51 saville 阅读(1358) | 评论 (1) 编辑

    摘要: 一、概述在软件开发过程中,我们有时候需要保证一个类仅有一个实例,比如在一个电脑用户下只能运行一个outlook实例。这时就需要用到单件模式。二、单件模式单件模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。。单件模式的结构图如下:Singleton负责创建自己的唯一实例,并定义一个Instance方法允许客户访问该实例。三、示例先来看看最简单的单件模式实现例子。 1 class SimpleSingleton 2 { 3 private static SimpleSingleton _instance; 4 5 private Simp...阅读全文
    posted @ 2012-01-06 09:29 saville 阅读(796) | 评论 (1) 编辑

    摘要: 一、概述在软件开发过程中,我们可能会希望在不暴露一个集合对象内部结构的同时,可以让外部代码透明地访问其中包含的元素。迭代器模式可以解决这一问题。二、迭代器模式迭代器模式提供一种方法顺序访问一个集合对象中的各个元素,而又不需暴露该对象的内部表示。迭代器模式的结构图如下:Iterator定义了访问和遍历元素的接口。ConcreteIterator表示具体的迭代器,它实现了Iterator接口。Aggregate定义创建相应迭代器对象的接口。ConcreteAggregate实现创建相应迭代器对象的接口,返回ConcreteIterator的一个实例。三、示例在C#中,实现迭代器模式是非常方便的,特阅读全文
    posted @ 2011-12-19 13:39 saville 阅读(238) | 评论 (0) 编辑

    摘要: 一、概述我们来实现一个企业的工资系统,该企业中不同级别的员工工资算法都不相同,针对该问题,最容易想到的莫过于在代码中堆积一大堆if…else…语句或者是switch…case…语句。如果该企业中不同级别的员工过多,或是对级别的调整比较频繁,那该系统就会显得复杂而脆弱。如何能将对象和算法解耦,从而使得在系统运行时能透明的改变对象的算法呢?这就到了策略模式大显身手的时候了。二、策略模式策略模式定义了一系列算法,把它们一个个封装起来,并且使它们可相互替换。该模式可使得算法能独立于使用它的客户而变化。策略模式的结构图如下:Context代表需要改变算法的那个对象,它维护了一个对Strategy对象的引阅读全文
    posted @ 2011-11-16 16:41 saville 阅读(1789) | 评论 (2) 编辑

    摘要: 一、概述在面向对象软件设计时,常常碰到某一个对象由于状态的不同而有不同的行为。如果用if else或是switch case等方法处理,对象操作及对象的状态就耦合在一起,碰到复杂的情况就会造成代码结构的混乱。在这种情况下,就可以使用状态模式来解决问题。二、状态模式状态模式允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。状态模式的结构图如下Context代表需要改变状态的那个对象,它维护了一个State实例,该实例定义了对象的当前状态。State定义了一个抽象类或是接口,用以封装与特定状态相关的行为。ConcreteState实现了State定义的行为。三、示例本文实现阅读全文
    posted @ 2011-10-13 14:20 saville 阅读(1197) | 评论 (7) 编辑

    摘要: 一、概述在软件开发中,对某一项操作往往有固定的算法结构,而具体的子步骤会因为不同的需要而有所不同。如何可以在稳定算法结构的同时来灵活应对子步骤变化的需求呢?二、模板方法模板方法是一种常见的设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法的结构图如下AbstractClass是抽象类,定义了抽象的操作ConcreteClass实现了抽象操作中与子类相关的特定步骤。三、示例在这里以实现一个公司的薪资系统为例介绍一下模板方法的应用。首先定义抽象类,一般建议将抽象的操作定义为非虚public方法,将子类需要定阅读全文
    posted @ 2011-09-14 14:34 saville 阅读(1473) | 评论 (2) 编辑

    摘要: 一、概述通常来说,“行为请求者”与“行为实现者”是紧耦合的。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这些情况下,将“行为请求者”与“行为实现者”解耦,实现二者之间的松耦合就至关重要。命令模式是解决这类问题的一个比较好的方法。二、命令模式命令模式将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。命令模式的结构图如下Command定义了命令的接口ConcreteCommand实现Command接口,定义了具体的命令Client用于创建具体的命令并设定接收者Invoker要求阅读全文
    posted @ 2011-08-17 10:20 saville 阅读(347) | 评论 (1) 编辑

    摘要: 一、例子在软件开发中,我们往往会想要给某一类对象增加不同的功能。比如要给汽车增加ESP、天窗或者定速巡航。如果利用继承来实现,就需要定义无数的类,Car,ESPCar,CCSCar,SunRoofCar,ESPCCSCar……很容易就导致“子类爆炸”问题。上述“子类爆炸”问题的根源在于该解决方案利用继承来扩展功能,缺乏灵活性。那么如何能在扩展功能的同时避免“子类爆炸”呢?二、装饰者模式装饰者模式装饰者模式可以动态地给一个对象增加一些额外的职责。就增加功能来说,装饰者模式相比生成子类更为灵活。装饰者模式的结构图如下Component定义了一个接口,可以利用Decorator为实现了这个接口的对象阅读全文
    posted @ 2011-07-19 17:17 saville 阅读(1444) | 评论 (6) 编辑

    摘要: 前阵子,运行一个执行ETL处理的SSIS包时一直报错:“The buffer manager cannot create a temporary storage file on any path in the BufferTempStoragePath property. There is an incorrect file name or no permission.”,“A buffer failed while allocating 4062864 bytes.”,“Error 0x8007000E while loading package file "D:\SSIS\ETL阅读全文
    posted @ 2011-06-03 09:20 saville 阅读(144) | 评论 (0) 编辑
  • 相关阅读:
    使用C++为对象分配与释放内存时的几个好习惯
    OGRE渲染流程
    【问题解决记录】无法识别的标志“-sdlMode”,在“p2”中
    四元数 Quaternion
    《The Cg Tutorial》阅读笔记——凹凸贴图 Bump Mapping
    尝试优化骨骼动画计算的意外收获——使用嵌入式汇编对float转int进行优化
    Model 的 Meta 选项
    dns资料
    ansible中的变量
    DockerFile与docker-compose.yml是什么
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2917099.html
Copyright © 2020-2023  润新知