Flyweight definition:
Avoid the overhead of a large number of small classes with the same content (such as memory consumption), so that everyone can share a class (Meta class ).
Why?
The principle of object-oriented language is that everything is an object, but if it is used, sometimes the number of objects may appear very large. For example, if the word processing software uses every text as an object, there are thousands of words, and the number of objects is several thousand, which undoubtedly consumes memory. Therefore, we still need to "seek the same ground while reserving differences" to find out what these object groups have in common and design a metadata class, encapsulate classes that can be shared. In addition, some features depend on the application context and cannot be shared. In Flyweight, the two important concepts are internal states intrinsic and external States extrinsic.
To put it bluntly, we need to first create an original model and then generate a specific model with different characteristics in different scenarios and environments. Obviously, we need to generate different new objects here, therefore, the Factory mode is often used in the Flyweight mode. the internal state of Flyweight is used for sharing. Flyweight factory is responsible for maintaining a Flyweight pool (mode pool) to store internal State objects.
The Flyweight mode is a mode for improving program efficiency and performance, which greatly speeds up program running. there are many applications: for example, if you want to read a series of strings from a database and many of these strings are repeated, we can store these strings in the Flyweight pool.
How to use it?
Let's start with the Flyweight abstract interface:
Program code:
Public InterfaceFlyweight { Public VoidOperation (ExtrinsicState state ); } // The abstract data type used in this mode (self-designed) Public InterfaceExtrinsicState {} |
The following figure shows the specific implementation of the interface (ConcreteFlyweight) and increases the memory space for the internal status. ConcreteFlyweight must be shareable and must be saved in any internal status (intrinsic). That is to say, concreteFlyweight must be independent of its application environment.
Program code:
Public ClassConcreteFlyweightImplementsFlyweight { PrivateIntrinsicState state; Public VoidOperation (ExtrinsicState state) { // Specific operation } } Of course, not all Flyweight implementation subclasses need to be shared, so there is another non-shared ConcreteFlyweight: |
Program code:
Public ClassUnsharedConcreteFlyweightImplementsFlyweight { Public VoidOperation (ExtrinsicState state ){} } |
Flyweight factory is responsible for maintaining a Flyweight pool (storing the internal status). When the client requests a shared Flyweight, the factory first searches whether the pool is applicable. If yes, factory simply returns and sends this object. Otherwise, it creates a new object, adds it to the pool, and then returns the object. pool
Program code:
Public ClassFlyweightFactory { // Flyweight pool PrivateHashtable flyweights =NewHashtable (); PublicFlyweight getFlyweight (Object key ){ Flyweight flyweight = (Flyweight) flyweights. get (key ); If(Flyweight = null ){ // Generate a new ConcreteFlyweight Flyweight =NewConcreteFlyweight (); Flyweights. put (key, flyweight ); } ReturnFlyweight; } } |
Now, the basic framework of the Flyweight mode is ready. Let's look at how to call it:
Program code:
FlyweightFactory factory =NewFlyweightFactory (); Flyweight fly1 = factory. getFlyweight ("Fred "); Flyweight fly2 = factory. getFlyweight ("Wilma "); ...... |
From the call point of view, it seems like a pure Factory use, but the secret lies in the internal design of the Factory.
The Flyweight mode is applied to XML and other data sources.
As we have mentioned above, when a large number of strings are read from the data source, there must be duplicates among them, we can use the Flyweight mode to improve efficiency. Take the recording CD as an example. In an XML file, stores multiple CD files.
Each CD has three fields:
1. Release date (year)
2. The Creator's name and other information (artist)
3. recording tracks (title)
The Creator's name may be repeated, that is, there may be multiple CDs of different tracks of the same artist in different periods. we use "creator name" as the shared ConcreteFlyweight. the other two fields are used as UnsharedConcreteFlyweight.
First, let's take a look at the content of the XML file of the Data source:
Program code:
<? Xml version = "1.0"?> <Collection>
<Cd> <Title> Another Green World </title> <Year> 1978 </year> <Artist> Eno, Brian </artist> </Cd>
<Cd> <Title> Greatest Hits </title> <Year> 1950 </year> <Artist> Holiday, Billie </artist> </Cd>
<Cd> <Title> Taking Tiger Mountain (by strategy) </title> <Year> 1977 </year> <Artist> Eno, Brian </artist> </Cd> ....... </Collection> |
Although there are only three CD examples in the above example, CD can be considered as a large number of repeated sub-classes, because there are only three fields in the example, and there are repeated (publisher name ).
CD is similar to the above interface Flyweight:
Program code:
Public ClassCD {
PrivateString title; Private IntYear; PrivateArtist artist;
PublicString getTitle (){ReturnTitle ;} Public IntGetYear (){ReturnYear ;} PublicArtist getArtist (){ReturnArtist ;}
Public VoidSetTitle (String t) {title = t ;} Public VoidSetYear (IntY) {year = y ;} Public VoidSetArtist (Artist a) {artist = ;}
} |
Use "creator name" as the shared ConcreteFlyweight:
Program code:
Public ClassArtist { // Internal status PrivateString name; // Note that Artist is immutable. String getName (){ReturnName ;} Artist (String n ){ Name = n; } } |
Let's take a look at the Flyweight factory, which is specifically used to make the above shareable ConcreteFlyweight: Artist
Program code:
Public ClassArtistFactory { Hashtable pool =NewHashtable (); Artist getArtist (String key ){ Artist result; Result = (Artist) pool. get (key ); //// Generate a new Artist If(Result = null ){ Result =NewArtist (key ); |