享元模式
- 格式:doc
- 大小:215.00 KB
- 文档页数:20
享元模式的原理与实际项目中的应用场景享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少对象的创建和内存消耗,以提高系统的性能和效率。
该模式通过共享相似对象的内部状态,而对不同的外部状态进行独立处理,从而实现对象的共享复用。
一、原理享元模式的核心思想是将对象分为内部状态(Intrinsic State)和外部状态(Extrinsic State)。
内部状态是对象共享的部分,存储在享元池(Flyweight Pool)中,可以被多个对象共享使用。
外部状态是对象特定的部分,在外部环境中可能不同,需要由客户端传递给享元对象。
通过内部状态和外部状态的分离,多个对象可以共享同一个享元对象,从而减少了对象的创建和内存消耗。
当需要使用某个对象时,从享元池中获取相应的享元对象,并将外部状态传递给该对象,进行特定的操作,使用完毕后再将对象返回到享元池。
二、实际项目中的应用场景1.图形编辑器在图形编辑器中,可能会遇到大量的图形对象,如矩形、圆形等。
这些图形对象之间具有一些共性,如大小、颜色等。
利用享元模式,可以将这些共性抽象成为内部状态,而将不同的位置作为外部状态。
这样可以大大减少对象的数量,提高系统的效率和性能。
2.连接池在数据库连接的管理中,连接池是一种常见的技术,用于提高数据库的操作效率。
连接池中的连接对象可以被多个线程共享使用,而每个线程使用连接时需要传递相应的用户名、密码等外部状态。
通过享元模式,可以将连接对象的内部状态和外部状态进行分离,实现对象的复用,提高数据库操作的效率。
3.游戏场景中的粒子系统在游戏开发中,粒子系统被广泛应用于实现各种特效,如爆炸、雨、雪等。
每个粒子对象都具有共性,如大小、颜色、速度等,而位置是每个粒子特有的外部状态。
通过享元模式,可以共享相同的粒子对象,减少对象的创建,提高游戏的性能和流畅度。
4.文本编辑器在文本编辑器中,字符是基本的单位,每个字符都有相应的ASCII码和字体样式。
java享元模式举例享元模式(Flyweight Pattern)是一种结构型设计模式,它用于最大程度地减少共享对象的数量,以减小内存占用和提高性能。
享元模式通过共享相似对象的部分状态来降低对象的存储开销。
下面是一个简单的Java享元模式的示例,以表示不同树的位置,其中一些树的位置相同:首先,创建享元接口`Tree`,它定义了树的位置:```javainterface Tree {void display(int x, int y);}```然后,创建具体享元类`TreeType`,它包含了树的共享状态和显示树的方法:```javaclass TreeType implements Tree {private final String name;public TreeType(String name) { = name;}@Overridepublic void display(int x, int y) {System.out.println("Tree " + name + " is located at (" + x + "," + y + ")");}}```接下来,创建享元工厂类`TreeFactory`,它负责维护和返回共享的树类型对象:```javaimport java.util.HashMap;import java.util.Map;class TreeFactory {private static Map<String, TreeType> treeTypes = new HashMap<>();static TreeType getTreeType(String name) {TreeType treeType = treeTypes.get(name);if (treeType == null) {treeType = new TreeType(name);treeTypes.put(name, treeType);}return treeType;}}```最后,创建客户端代码,它使用享元模式来创建和显示树:```javapublic class Main {public static void main(String[] args) {TreeFactory treeFactory = new TreeFactory();Tree tree1 = new TreeType("Maple");Tree tree2 = new TreeType("Oak");Tree tree3 = new TreeType("Maple");tree1.display(10, 20); // 创建新树对象tree2.display(30, 40); // 创建新树对象tree3.display(50, 60); // 共享现有树对象,树类型为"Maple"}}```在这个示例中,`TreeType` 表示具体树的类型,`TreeFactory` 维护了树类型对象的缓存。
23种设计模式书23种设计模式书是指《设计模式》一书中所介绍的23种常见的软件设计模式。
这些设计模式是在软件开发中经过验证和应用的最佳实践,可以帮助开发人员解决各种常见的设计问题。
本文将依次介绍这23种设计模式,并对每种模式进行简要的说明和应用场景的介绍,以帮助读者更好地理解和应用这些设计模式。
1. 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
2. 工厂模式(Factory):将对象的创建和使用分离,通过工厂类来创建对象。
3. 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体的类。
4. 建造者模式(Builder):将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
5. 原型模式(Prototype):通过复制已有对象来创建新对象,避免了创建过程的复杂性。
6. 适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。
7. 桥接模式(Bridge):将抽象部分和实现部分分离,使它们可以独立变化。
8. 过滤器模式(Filter):使用标准来过滤一组对象,获取满足条件的子集。
9. 组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。
10. 装饰器模式(Decorator):动态地给一个对象添加额外的职责,同时又不改变其结构。
11. 外观模式(Facade):提供一个统一的接口,用来访问子系统中的一群接口。
12. 享元模式(Flyweight):通过共享对象来有效地支持大量细粒度的对象。
13. 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
14. 责任链模式(Chain of Responsibility):将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。
15. 命令模式(Command):将一个请求封装成一个对象,从而可以用不同的请求对客户进行参数化。
享元模式是一种常见的设计模式,它可以有效地减少系统中对象的数量,提高系统的性能和可扩展性。
以下是享元模式的常见应用场景:
1.大量共享对象的场景:在一些系统中,可能会存在大量的共享对象,例如数据库连接池、线程池等。
这些对象可以通过享元模式来实现共享,减少对象的创建和销毁,提高系统的性能和可扩展性。
2.大数据量的场景:在一些需要处理大量数据的系统中,可能会存在大量的重复对象,例如图像处理中的像素点、文本处理中的单词等。
这些对象可以通过享元模式来共享,减少对象的创建和内存消耗,提高系统的性能和可扩展性。
3.高并发的场景:在一些高并发的系统中,可能会存在大量的请求,例如电商网站的购物车、在线游戏的排行榜等。
这些对象可以通过享元模式来共享,减少对象的创建和销毁,提高系统的并发处理能力和响应速度。
4.分布式系统中的对象共享:在分布式系统中,可能会存在大量的对象需要在不同的节点之间共享,例如分布式缓存系统、分布式锁等。
这些对象可以通过享元模式来共享,减少对象的网络传输和存储开销,提高系统的性能和可扩展性。
综上所述,享元模式适用于需要共享大量对象的系统,通过共享对象来减少系统的资源消耗和提高系统的性能和可扩展性。
系统架构设计师23种设计模式记忆口诀设计模式分为三种类型:创建型设计模式(4种:工厂模式(工厂模式、抽象工厂模式)、单例模式、原型模式、建造者模式)主要用户创建对象;创建型:创建模式创对象。
工厂模式要抽象;单例只有一个类;拷贝原型创对象;建造复杂的对象。
解释:创建模式主要用于创建对象。
工厂模式根据业务需要分为简单工厂模式、工厂方法模式和抽象工厂模式;原型模式用于创建重复的对象,通过拷贝这些原型创建新的对象;建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。
------------------------------------------------------------------------------- 结构型设计模式(8种:代理模式、外观模式、装饰器模式、享元模式、组合模式、适配器模式、桥接模式、过滤器)主要关注类和对象的组合;结构型:结构组合类对象。
代理外观装饰器;享元组合适配器;桥接不能过滤器。
代理对象访问者;外观一致的接口;装饰动态添职责;享元共享搞对象。
组合对象像棵树;适配接口能兼容;桥接抽象与实现;不同标准来过滤。
解释:结构型设计模式主要关注类和对象的组合。
主要有代理模式、外观模式、装饰器模式、享元模式、组合模式、适配器模式、桥接模式不能继承,过滤器模式。
代理模式为其他对象提供一种代理以控制对这个对象的访问;外观模式通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式,这是典型的”迪米特原则“;装饰器模式动态地给一个对象添加一些额外的职责;享元模式运用共享技术来有效地支持大量细粒度对象的复用;组合模式将对象组合成树形结构以表示"部分-整体"的层次结构;适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作;桥接模式将抽象部分与实现部分分离,使它们都可以独立的变化;过滤器模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来行为型设计模式(11种:模板模式、策略模式、迭代器模式、中介模式、备忘录模式、解释器模式、观察者模式、访问者模式、状态模式、责任链模式、命令模式)主要关注对象间通信的问题。
设计模式----Flyweight(享元)模式GOF:运用共享技术有效地支持大量细粒度的对象。
解释一下概念:也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。
比如说(这里引用GOF书中的例子)一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象。
如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了。
那么如果要是每个字母都共享一个对象,那么就大大节约了资源。
在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweight(享元)模式中常出现Factory模式。
Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个对象存储池(Flyweight Pool)来存放内部状态的对象。
Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合很多,下面举个例子:先定义一个抽象的Flyweight类:package Flyweight;public abstract class Flyweight{public abstract void operation();}//end abstract class Flyweight在实现一个具体类:package Flyweight;public class ConcreteFlyweight extends Flyweight{private String string;public ConcreteFlyweight(String str){string = str;}//end ConcreteFlyweight(...)public void operation(){System.out.println("Concrete---Flyweight : " + string);}//end operation()}//end class ConcreteFlyweight实现一个工厂方法类:package Flyweight;import java.util.Hashtable;public class FlyweightFactory{private Hashtable flyweights = new Hashtable();//----------------------------1public FlyweightFactory() {}public Flyweight getFlyWeight(Object obj){Flyweight flyweight = (Flyweight) flyweights.get(obj);//----------------2if(flyweight == null) {//---------------------------------------------------3//产生新的ConcreteFlyweightflyweight = new ConcreteFlyweight((String)obj);flyweights.put(obj, flyweight);//--------------------------------------5}return flyweight;//---------------------------------------------------------6}//end GetFlyWeight(...)public int getFlyweightSize(){return flyweights.size();}}//end class FlyweightFactory这个工厂方法类非常关键,这里详细解释一下:在1处定义了一个Hashtable用来存储各个对象;在2处选出要实例化的对象,在6处将该对象返回,如果在Hashtable中没有要选择的对象,此时变量flyweight为null,产生一个新的flyweight存储在Hashtable中,并将该对象返回。
单例模式与享元模式设计模式中最为熟悉的莫过于这两种模式,⽽它们之间也有着很相似的地⽅。
单例模式(Singleton)的定义:是为了确保⼀个类只能产⽣⼀个实例,从⽽节省对象创建所花费的时间,从⽽对系统内存使⽤频率也会减低。
享元模式(FlyWeight)的定义:是为系统中存在多个相同的对象,那么只需要共享⼀个对象的拷贝。
个⼈认为从这两个模式的定义⽽⾔,它们的⽬的是⼀样的,⾄少就内存的开销问题这点,两者是相同的。
⽽享元模式可以看成是单例的⼀个扩展。
下⾯是单例的实现⽅式:1public class SingleDevise {23private SingleDevise(){}45private static SingleDevise single=null;67public static synchronized SingleDevise getIntance(){8if(single==null){9 single=new SingleDevise();10 }11return single;1213 }14 }上⾯的代码接对象的⽣成做了延迟加载,它的时耗会⾼⼀点,但是确保系统启动时没有额外的负载,这⾥我还想说的时,虽然就单例模式中的私有构造函数,就⼀般做法时没法在外⾯得到它的实例对象,但是对于极端的做法通过反射机制还是能够解决这种问题的。
所以我觉得单例的实现还不是很完善。
⽽享元模式的实现相对会⽐较复杂点。
⾸先它的⾓⾊需要有享元⼯⼚,抽象享元,具体享元类,main但是实现还是⽐较容易的public class FlyweightFactory {Map<String, Employer> map=new HashMap<String, Employer>();public Employer getEmployer(String name){Employer e=map.get(name);if(e==null){System.out.println("map is empty");e=new Employer(name);map.put(name, e);}return e;}}享元⼯⼚是这个模式的核⼼,了解这个类就可以了。
面向对象设计的23个设计模式详解面向对象设计是一种广泛应用于软件开发的思想,其核心在于将数据和操作封装在一起形成对象,并通过各种方式进行交互和组合,从而实现复杂的功能。
在这一过程中,设计模式起到了非常重要的作用,可以有效地提高代码的可读性、可维护性和可扩展性。
本文将对23种常见的设计模式进行详解。
一、创建型模式1.简单工厂模式简单工厂模式属于创建型模式,其目的是提供一个工厂类,使得创建对象的过程更加简单。
在这种模式中,使用者只需要提供所需对象的参数,而无需关心对象的具体实现细节。
简单工厂模式适合于对象创建过程较为简单的情况。
2.工厂方法模式工厂方法模式是简单工厂模式的进一步扩展,其核心在于将工厂类进行接口抽象化,使得不同的工厂类可以创建不同的对象实例。
工厂方法模式适合于对象创建过程较为复杂的情况。
它可以为工厂类添加新的产品类型,而不会影响原有的代码。
3.抽象工厂模式抽象工厂模式是工厂方法模式的进一步扩展,其目的是提供一个可以创建一系列相关或者独立的对象的接口。
在抽象工厂模式中,使用者只需要关心所需对象组合的类型,而无需关注对象的具体实现过程。
4.建造者模式建造者模式也是一种创建型模式,其目的在于将复杂对象分解为多个简单的部分,并将其组装起来形成复杂对象实例。
在建造者模式中,使用者只需要关注所需对象以及它们的组合方式,而无需关心对象的具体实现过程。
5.原型模式原型模式是一种基于克隆的创建型模式,其核心在于通过复制现有的对象实例来创建新的对象。
在原型模式中,对象实例的创建过程与对象所包含的状态密切相关。
原型模式适合于创建复杂对象实例,且这些对象实例之间是相对独立的情况。
二、结构型模式6.适配器模式适配器模式是一种结构型模式,其目的在于将一个类的接口转换为另一个类所能使用的接口。
在适配器模式中,使用者可以通过不同的适配器实现对象之间的互相调用。
7.桥接模式桥接模式是一种结构型模式,其目的在于将抽象部分与实现部分相互分离,从而使得两者可以独立变化。
23种设计模式简单明了1. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。
2. 工厂模式(Factory Pattern):定义创建对象的接口,但将实际创建对象的过程推迟到子类中。
3. 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关对象的接口,而无需指定具体的类。
4. 建造者模式(Builder Pattern):将一个复杂对象的创建与表示分离,使同样的构建过程可以创建不同的表示。
5. 原型模式(Prototype Pattern):通过复制现有的对象来创建新对象。
6. 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。
7. 桥接模式(Bridge Pattern):将抽象与实现分离,使它们可以独立变化,从而减少两者之间的耦合。
8. 过滤器模式(Filter Pattern):通过某种条件来过滤一组对象。
9. 组合模式(Composite Pattern):将对象组合成树形结构,以表示 "部分-整体" 的层次结构。
10. 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。
11. 外观模式(Facade Pattern):隐藏系统的复杂性,并向客户端提供一个简化的接口。
12. 享元模式(Flyweight Pattern):共享对象,以便有效地支持大量细粒度的对象。
13. 代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问。
14. 责任链模式(Chain of Responsibility Pattern):将请求的发送者和接收者解耦,并让多个对象都有机会处理这个请求。
15. 命令模式(Command Pattern):将请求封装成对象,从而允许使用不同的请求、队列或者日志请求。
16. 解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
23种设计模式范文设计模式是软件开发中常用的解决方案模式,它们代表了在面对特定问题时的最佳实践和经验总结。
设计模式可以帮助我们更好地组织和设计代码,提高代码的可读性、可维护性和可扩展性。
在本文中,我们将介绍23种常用的设计模式,并分别讨论它们的实现原理和在实际开发中的应用场景。
1. 单例模式(Singleton Pattern)单例模式是最简单的设计模式之一,它确保一个类只有一个实例,并提供一个全局访问点。
在实现上,可以通过将构造函数私有化,然后提供一个静态方法返回实例来实现单例。
应用场景:在需要实现全局唯一访问点的场景下,比如线程池、配置管理器等。
2. 工厂模式(Factory Pattern)工厂模式是用来创建对象的一种模式,它将对象的创建和实现分离,使得代码更易于维护和扩展。
工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式等几种不同的变体。
应用场景:在需要根据不同条件创建不同对象的场景下,比如数据库连接、日志记录等。
3. 抽象工厂模式(Abstract Factory Pattern)抽象工厂模式是工厂模式的一种扩展,它提供一个创建一系列相关或相互依赖对象的接口,而无需指定实际的类。
抽象工厂模式将一组工厂类封装起来,使其可以交换或者替换。
应用场景:在需要创建一组相关对象(如界面主题、操作系统等)并且需要保持一致性的场景下。
4. 建造者模式(Builder Pattern)建造者模式是用来生成复杂对象的一种模式,它将对象的构建与其表现分离,采用逐步构建的方式生成对象,可以让客户端不需要知道具体的构建细节。
应用场景:在构造过程比较复杂,需要多个组件协同工作的场景下,比如构建复杂的UI界面。
5. 原型模式(Prototype Pattern)原型模式是用来克隆对象的一种模式,它通过复制已有对象的原型来创建新的对象,避免了通过构造函数创建对象和初始化成员变量的重复过程。
应用场景:在需要创建大量相似对象或者初始化成本较高的对象时,可以使用原型模式。
享元模式(Flyweight Pattern)面向对象的代价面向对象很好地解决了系统抽象性的问题,同时在大多数情况下,也不会损及系统的性能。
但是,在某些特殊的应用中下,由于对象的数量太大,采用面向对象会给系统带来难以承受的内存开销。
比如:图形应用中的图元等对象、字处理应用中的字符对象等。
动机(Motivate):采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价--------主要指内存需求方面的代价。
如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来进行操作?意图(Intent):运用共享技术有效地支持大量细粒度的对象。
-------《设计模式》GOF 结构(Struct):适用性:当以下所有的条件都满足时,可以考虑使用享元模式:1、一个系统有大量的对象。
2、这些对象耗费大量的内存。
3、这些对象的状态中的大部分都可以外部化。
4、这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
5、软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
满足以上的这些条件的系统可以使用享元对象。
最后,使用享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源。
因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。
生活中的例子:享元模式使用共享技术有效地支持大量细粒度的对象。
公共交换电话网(PSTN)是享元的一个例子。
有一些资源例如拨号音发生器、振铃发生器和拨号接收器是必须由所有用户共享的。
当一个用户拿起听筒打电话时,他不需要知道使用了多少资源。
对于用户而言所有的事情就是有拨号音,拨打号码,拨通电话。
代码实现:Flyweight在拳击比赛中指最轻量级,即“蝇量级”,这里翻译为“享元”,可以理解为共享元对象(细粒度对象)的意思。
提到Flyweight模式都会一般都会用编辑器例子来说明,这里也不例外,但我会尝试着通过重构来看待Flyweight模式。
考虑这样一个字处理软件,它需要处理的对象可能有单个的字符,由字符组成的段落以及整篇文档,根据面向对象的设计思想和Composite模式,不管是字符还是段落,文档都应该作为单个的对象去看待,这里只考虑单个的字符,不考虑段落及文档等对象,于是可以很容易的得到下面的结构图:1// "Charactor"2public abstract class Charactor3 {4//Fields5protected char _symbol;67protected int _width;89protected int _height;11protected int _ascent;1213protected int _descent;1415protected int _pointSize;1617//Method18public abstract void Display();19 }2021// "CharactorA"22public class CharactorA : Charactor23 {24// Constructor25public CharactorA()26 {27this._symbol = 'A';28this._height = 100;29this._width = 120;30this._ascent = 70;31this._descent = 0;32this._pointSize = 12;33 }3435//Method36public override void Display()37 {38 Console.WriteLine(this._symbol);39 }40 }4142// "CharactorB"43public class CharactorB : Charactor45// Constructor46public CharactorB()47 {48this._symbol = 'B';49this._height = 100;50this._width = 140;51this._ascent = 72;52this._descent = 0;53this._pointSize = 10;54 }5556//Method57public override void Display()58 {59 Console.WriteLine(this._symbol);60 }61 }6263// "CharactorC"64public class CharactorC : Charactor65 {66// Constructor67public CharactorC()68 {69this._symbol = 'C';70this._height = 100;71this._width = 160;72this._ascent = 74;73this._descent = 0;74this._pointSize = 14;75 }7677//Method78public override void Display()79 {80 Console.WriteLine(this._symbol);81 }82 }好了,现在看到的这段代码可以说是很好地符合了面向对象的思想,但是同时我们也为此付出了沉重的代价,那就是性能上的开销,可以想象,在一篇文档中,字符的数量远不止几百个这么简单,可能上千上万,内存中就同时存在了上千上万个Charactor对象,这样的内存开销是可想而知的。
进一步分析可以发现,虽然我们需要的Charactor实例非常多,这些实例之间只不过是状态不同而已,也就是说这些实例的状态数量是很少的。
所以我们并不需要这么多的独立的Charactor实例,而只需要为每一种Charactor状态创建一个实例,让整个字符处理软件共享这些实例就可以了。
看这样一幅示意图:现在我们看到的A,B,C三个字符是共享的,也就是说如果文档中任何地方需要这三个字符,只需要使用共享的这三个实例就可以了。
然而我们发现单纯的这样共享也是有问题的。
虽然文档中的用到了很多的A字符,虽然字符的symbol等是相同的,它可以共享;但是它们的pointSize却是不相同的,即字符在文档中中的大小是不相同的,这个状态不可以共享。
为解决这个问题,首先我们将不可共享的状态从类里面剔除出去,即去掉pointSize这个状态(只是暂时的 ),类结构图如下所示:1// "Charactor"2public abstract class Charactor3 {4//Fields5protected char _symbol;67protected int _width;89protected int _height;1011protected int _ascent;1213protected int _descent;1415//Method16public abstract void Display();17 }1819// "CharactorA"20public class CharactorA : Charactor 21 {22// Constructor23public CharactorA()24 {25this._symbol = 'A';26this._height = 100;27this._width = 120;28this._ascent = 70;29this._descent = 0;30 }3132//Method33public override void Display()34 {35 Console.WriteLine(this._symbol);36 }37 }3839// "CharactorB"40public class CharactorB : Charactor41 {42// Constructor43public CharactorB()44 {45this._symbol = 'B';46this._height = 100;47this._width = 140;48this._ascent = 72;49this._descent = 0;50 }5152//Method53public override void Display()54 {55 Console.WriteLine(this._symbol);56 }57 }5859// "CharactorC"60public class CharactorC : Charactor61 {62// Constructor63public CharactorC()64 {65this._symbol = 'C';66this._height = 100;67this._width = 160;68this._ascent = 74;69this._descent = 0;70 }7172//Method73public override void Display()74 {75 Console.WriteLine(this._symbol);76 }77 }好,现在类里面剩下的状态都可以共享了,下面我们要做的工作就是控制Charactor类的创建过程,即如果已经存在了“A”字符这样的实例,就不需要再创建,直接返回实例;如果没有,则创建一个新的实例。
如果把这项工作交给Charactor类,即Charactor类在负责它自身职责的同时也要负责管理Charactor实例的管理工作,这在一定程度上有可能违背类的单一职责原则,因此,需要一个单独的类来做这项工作,引入CharactorFactory类,结构图如下:1// "CharactorFactory"2public class CharactorFactory3 {4// Fields5private Hashtable charactors = new Hashtable();67// Constructor8public CharactorFactory()9 {10 charactors.Add("A", new CharactorA());11 charactors.Add("B", new CharactorB());12 charactors.Add("C", new CharactorC());13 }1415// Method16public Charactor GetCharactor(string key)17 {18 Charactor charactor = charactors[key] as Charactor; 1920if (charactor == null)21 {22switch (key)23 {24case "A": charactor = new CharactorA(); break;25case "B": charactor = new CharactorB(); break;26case "C": charactor = new CharactorC(); break;27//28 }29 charactors.Add(key, charactor);30 }31return charactor;32 }33 }到这里已经完全解决了可以共享的状态(这里很丑陋的一个地方是出现了switch语句,但这可以通过别的办法消除,为了简单期间我们先保持这种写法)。