Design Pattern - Structural Patterns - Flyweight Pattern

50 篇文章 0 订阅
37 篇文章 0 订阅

2007
2007


Section 6, Chapter 4
Section 2, Chapter 3


Flyweight Pattern


Concept

Put all the content from both books together, the highlights of Flyweight Pattern are listed as below:


  • The objects are small, which means the volume of the information they carry is not big;
  • The amount of such objects is big, which rises a concern of memory, and that is exactly the issue this pattern is meant to solve;
  • The information carried by those small objects can be categorized into two groups: intrinsic & extrinsic;
  • Intrinsic information can be reused again and again, and it therefore should not be specific to any scenario, that is why Christopher described it as independent of context, and this piece of info is usually referred as intrinsic state of the object;
  • Context is defined by Chris as the particular placement of each object in code flow, with the particular values and states associated with that context;
  • Extrinsic information are still be carried by those objects, but it is meant to be context-related, and in the pattern,it is computed on the fly at the expense of CPU power in order to save memory resource, so, it is a trade-off.
  • Extrinsic state can be computed either by the objects themselves, or by the clients, with the latter manner, you will need to provide the methods to accept those extrinsic data.
  • In Christopher's demonstration, there is no clear boundary between intrinsic info and extrinsic one, they can overlap, and intrinsic info can be used as default state, or overridden by extrinsic info to calculate a result in some cases as needed, but their values in the objects won't be overwritten by the extrinsic info.
  • In Christopher's design, there is a component called unshared flyweight, and in his example of text processing, the position of a character is stored as intrinsic information, and it is context related, so it cannot be shared as it only makes sense in some specific situations. Such info is passed through constructor by the context, and will not be changed. How this could be helpful is not revealed clearly in his demonstration, and he also gives following comments: "Since there is one unshared flyweight instance per context location, having intrinsic methods that associate with the context do not interfere with any other implementation of this object within the program...This gives us both the option of sharing objects or allowing many instances of objects to be created. This might be useful if we had a character that was only used rarely or needed special context-related conditions to be useful in the document, such as a paragraph element...The particular context of the unshared character object gives us back the intrinsic values from that context." However, I don't get it, the benefit is not so apparent without a concrete example.


Use

  • There is a very large number of objects (thousands) that may not fit in memory.
  • Most of the state can be kept on disk or calculated at runtime.
  • The remaining state can be factored into a much smaller number of objects with shared state.


There are:

  • Many objects to deal with in memory
  • Different kinds of state, which can be handled differently to achieve space savings
  • Groups of objects that share state
  • Ways of computing some of the state at runtime

You want to:

  • Implement a system despite severe memory constraints


Design


Photo Group Example by Judith:





Text Processing Example by Chris:



Illustration

Photo Gallery Example:

namespace FlyweightPattern {
	// Flyweight Pattern Judith Bishop Sept 2007

	public interface IFlyweight {
		void Load (string filename);
		void Display (PaintEventArgs e, int row, int col);
	}

	public struct Flyweight : IFlyweight {
		// Intrinsic state
		Image pThumbnail;

		public void Load(string filename) {
			pThumbnail = new Bitmap("images/"+filename).GetThumbnailImage(100, 100, null, new IntPtr());
		}

		public void Display(PaintEventArgs e, int row, int col) {
			e.Graphics.DrawImage(pThumbnail, col*100+10, row*130+40, pThumbnail.Width, pThumbnail.Height);
		}

	}


	public class FlyweightFactory {
		// Keeps an indexed list of IFlyweight objects in existence
		Dictionary<string, IFlyweight> flyweights = new Dictionary<string, IFlyweight>();

		public FlyweightFactory() {
			flyweights.Clear( );
		}

		public IFlyweight this[string index] {
			get {
				if (!flyweights.ContainsKey(index))
					flyweights[index] = new Flyweight();
				return flyweights[index];
			}
		}
	}



	class Client {
		// Shared state - the images
		static FlyweightFactory album = new FlyweightFactory();

		// Unshared state - the groups
		static Dictionary<string, List<string>> allGroups = new Dictionary<string, List<string>>();

		public void LoadGroups() {
			var myGroups = new [] {
				new {
					Name = "Garden",
					Members = new [] {"pot.jpg", "spring.jpg", "barbeque.jpg", "flowers.jpg"}
				},
				new {
					Name = "Italy",
					Members = new [] {"cappucino.jpg","pasta.jpg", "restaurant.jpg", "church.jpg"}
				},
				new {
					Name = "Food",
					Members = new [] {"pasta.jpg", "veggies.jpg", "barbeque.jpg","cappucino.jpg","lemonade.jpg" }
				},
				new {
					Name = "Friends",
					Members = new [] {"restaurant.jpg", "dinner.jpg"}
				}
			};

			// Load the Flyweights, saving on shared intrinsic state
			foreach (var g in myGroups) { // implicit typing
				allGroups.Add(g.Name, new List<string>());
				foreach (string filename in g.Members) {
					allGroups[g.Name].Add(filename);
					album[filename].Load(filename);
				}
			}
		}

		public void DisplayGroups(Object source, PaintEventArgs e) {
			// Display the Flyweights, passing the unshared state
			int row;
			foreach(string g in allGroups.Keys) {
				int col;
				e.Graphics.DrawString(g, new Font("Arial", 16), new SolidBrush(Color.Black), new PointF(0, row*130+10));
				foreach (string filename in allGroups[g]) {
					album[filename].Display(e, row, col);
					col++;
				}
				row++;
			}
		}

	}


	class Window : Form {
		Window() {
			this.Height = 600;
			this.Width = 600;
			this.Text = "Picture Groups";
			Client client = new Client();
			client.LoadGroups();
			this.Paint += new PaintEventHandler(client.DisplayGroups);
		}

		static void Main() {
			Application.Run(new Window());
		}
	}

}


And in this example:

The Client class -> client.

Interface IFlyweight -> specification of an image view drawer.

Class Flyweight -> the thumbnail drawer.

The intrinsic state -> thumbnail.

The extrinsic state -> full image.

The unshared information -> the data of a group.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值