0. Excerpt from design pattern
-
Question:
In a document editor, each character in the document can be described as an object:
Too memory consuming, a small document may contain thousands of character objects. -
Solution:
Shared object. Each character is represented by an object. All the characters in the document share this object.
All characters refer to flyweight pool to avoid repetition
What about status information? The status information (font, color, etc.) of each character is represented by an external object
These states can also be shared. For example, the text of the whole paragraph adopts the same font and color.
I Targeted problems
Different customers have similar needs, such as building a website. The initial practice is to allocate a space to each customer and copy a code. In other words, one more website is one more class instance, which wastes a lot of resources.
Solution: share the code core and database, and use the user ID to distinguish different users. The specific data and templates can be different.
II Shared element mode (only the implementation of shared part)
2.1 structure diagram and code
- Sharing meta mode: using sharing technology to effectively support a large number of fine-grained objects.
-
Flyweight: super class or interface of all specific meta classes. Through this interface, flyweight can accept and act on external states.
abstract class Flyweight { public abstract void Operation (int extrinsicstate); }
-
ConcreteFlyweight: inherit Flyweight superclass or implement Flyweight interface, and increase storage space for internal state.
class ConcreteFlyweight extends Flyweight { public override void Operation(int extrinsicstate) { Console.WriteLine ("specific Flyweight:" +extrinsicstate); } }
-
UnsharedConcreteFlyweight: no shared Flyweight subclass is required. Because Flyweight interface sharing is possible, but it does not force sharing.
class UnsharedConcreteFlyweight extends Flyweight { public override void Operation(int extrinsicstate) { Console.Writeine("Specific information not shared Flyweight:"+ extrinsicstate); } }
-
FlyweightFactory: a meta factory used to create and manage Flyweight objects. It is mainly used to ensure reasonable sharing of Flyweight. When a user requests a Flyweight, the FlyweightFactory object provides a created instance or creates a
class FlyweightFactory { private Hashtable flyweights = new Hashtable(); //When initializing the factory, Mr. is divided into three instances flyweights.Add("X", new ConcreteFlyweight()); flyweights.Add("Y", new ConcreteFlyweight()); flyweights.Add("Z", new ConcreteFlyweight()); //Obtain the generated instance according to the client request public Flyweight GetFlyweight(String key) { return ((Flyweight)flyweights[key]) } }
-
Client: the client is associated with the shared element factories FlyweightFactory, ConcreteFlyweight and unshared ConcreteFlyweight, that is, it knows the shared Flyweight and unshared Flyweight
static void Main(string[] args) { int extrinsicstate = 22; //Code external status FlyweightFactory f = new FlyweightFactory(); Flyweight fx = f.GetFlyweight("x"); fx.Operation(--extrinsicstate); Flyweight fy = f.GetFlyweight("Y"); fy.Operation(--extrinsicstate); Flyweight fz = f.GetFlyweight("z"); fz.Operation(--extrinsicstate); UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight(); uf.Operation(--extrinsicstate); Console.Read(); } /* Result representation Specific Flyweight: 21 Specific Flyweight: 20 Specific Flyweight: 19 Specific flyweight not shared: 18 */
-
Note: it can also be lazy. Do nothing during initialization. When the user calls, judge whether the object is null to decide whether to instantiate.
2.2. Code applied to web site
The website should have an abstract class and a concrete website class, and then generate objects through the website factory.
-
Website abstract class
abstract class WebSite { public abstract void Use(); }
-
Specific website class
class ConcreteWebSite extends WebSite { private string name = ""; public ConcreteWebSite(string name) { this.name = name; @override public void Use() { Console.WriteLine ("Site classification:" + name) } } }
-
Website factory class
class WebSiteFactory { private Hashtable flyweights = new Hashtable(); //Get site classification public WebSite GetWebSiteCategory(string key) { if(!flyweights.ContainsKey(key)) flyweights.Add(key,new ConcreteWebSite(key)); return ((WebSite)flyweights[key]); } //Get the total number of site categories public int GetWebSiteCount() { return flyweights.Count; } }
-
Client code
static void Main(string[] args) { WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory (""Product display"); fx.Use(); WebSite fy = f.GetWebSiteCategory(""Product display"); fy.Use(); WebSite fz = f.GetWebSiteCategory("Product display"); fz.Use(); WebSite fl = f.GetWebSiteCategory("Blog"); fl.Use(); WebSite fm = f.GetWebSiteCategory("Blog") ; fm.Use(); WebSite fn = f.GetWebSiteCategory("Blog"); fn.Use(); Console.WriteLine ("The total number of site categories is{0}",f.GetWebSiteCount()); Console.Read(); }
result:
Website category: product displayWebsite category: product display
Website category: product display
Website category: Blog
Website category: Blog
Website category: Blog
The total number of website categories is 2
In fact, this writing does not reflect the differences between objects, but only the parts they share.
III Internal state and external state
-
Internal state of meta object: the shared part inside the meta object and will not change with the environment
External state: a state that changes with the environment and cannot be shared
Applicable scenario: sometimes it is necessary to generate a large number of fine-grained class instances to represent data. If it is found that these instances are basically the same except for several parameters, sometimes the number of classes to be instantiated can be reduced: move those parameters outside the class instance and pass them in during method call, so as to reduce the number of single instances through sharing.The internal state is stored in the ConcreteFlyweight object, while the external object is stored or calculated by the client object and passed to it when calling the operation of the Flyweight object. In other words, the customer account is an external status and should be handled by a special object
-
Code structure diagram:
-
User class: used for the customer account of the website. It is the external status of the "website" class
public class User { private string name; public User(string name) { this.name = name; } public string get() { return name; } }
-
Website abstract class
abstract class WebSite { public abstract void Use(User user); }
-
Specific website class
class ConcreteWebSite extends WebSite { private string name = ""; public ConcreteWebSite(String name) { this.name = name; } @override public void Use(User user)//Specifically implement Use, and pass in the parameter User to obtain the external state { Console.WriteLine("Website classification:" + name + "User:" + user.Name); } }
-
Website factory class
class WebSiteFactory { private Hashtable flyweights = new Hashtable(); //Get site classification public WebSite GetWebSiteCategory(String key) { if (!flyweights.ContainsKey(key)) flyweights.Add(key, new ConcreteWebSite(key)); return ((WebSite)flyweights[key]); } //Get the total number of site categories public int GetWebSiteCount() { return flyweights.Count; } }
-
Client code
static void Main(string[] args) { WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Product display"); fx=f.Use(new User("side dish")); WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Product display"); fx=f.Use(new User("Big bird")); WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Product display"); fx=f.Use(new User("Jiao Jiao")); WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Blog"); fx=f.Use(new User("Peach Valley six Immortals")); WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Blog"); fx=f.Use(new User("South China Sea crocodile God")); WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.GetWebSiteCategory("Blog"); fx=f.Use(new User("Old urchin")); Console.WriteLine ("The total number of website categories obtained is{0}",f.GetWebSiteCount()); Console.Read(); }
The results show that although the website is used for six different users, there are actually only two website instances.
Website classification: product display user: side dishesWebsite category: product display user: big bird
Website category: product display user: Jiao Jiao
Website classification: blog user: South China Sea crocodile God
Website classification: blog user: Taogu Liuxian
Website category: blog user: old urchin
The total number of website categories is 2
-
IV Some problems
-
Why should unshared concrete flyweight exist?
Because although we need to share objects most of the time to reduce memory loss, we may not need to share them occasionally. It can solve the problems that do not need to share objects -
When to use the meta mode?
If an application uses a large number of objects, and a large number of these objects cause great storage overhead, it should be considered;
In addition, most states of objects can be external states. If you delete the external states of objects, you can replace many groups of objects with relatively few shared objects. At this time, you can consider using the shared element mode -
Disadvantages:
To use the sharing mode, you need to maintain a list that records all the existing sharing elements in the system, which itself requires resources,
In addition, the meta model makes the system more complex.
In order to share objects, some states need to be externalized, which complicates the logic of the program.
Therefore, it should be worth using meta mode when there are enough object instances to share -
Application:
-
String A="a";
String B ="a";
The two addresses are the same, with only one instance.
-
The same state of go is two colors - internal state, and the change is orientation - external state, so only two instances are needed
-