原型模式
这段时间在研究设计模式,前几天学习了原型模式,今天跟大家讨论下!
原型模式属于创建型模式,它与其他创建型模式不一样的是:它通过复制已有对象来产生新的对象。
1 结构图如下:
在这里通过原型管理器去管理新生成的对象,用户不需要关心对象的生成细节。先注册原型类,再通过克隆原型生成具体的对象。与工厂方法模式相比,少了很多与产品平行的工厂方法类。
2 Demo设计图
这几天做了一个与原型模式配套的小demo,请大家多多指教!
这个小程序主要核心功能模块:画板、调色板、颜色管理器、颜色原型和具体颜色画笔。
3 代码实现
画板类实现:
画板根据调色板上选择的颜色,画出相应颜色的线,核心代码用到了画图的知识,这块也是现学现卖,写的不好的请大家指出!
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; using PrototypePattern.Color; using System.Xml; namespace PrototypePattern.Draw { /// <summary> /// 画板类 /// </summary> public class DrawBoard { private PictureBox pb; private Bitmap p_bmp; private Graphics dgGraphic;//画布 private Palette palette;//调色板类,提供当前画笔(具体代码如下) private Point preP; public DrawBoard(ref PictureBox p, ref Palette palette) { this.palette = palette; this.pb = p; p_bmp = new Bitmap(this.pb.Width, this.pb.Height); dgGraphic = Graphics.FromImage(p_bmp); this.pb.Image = p_bmp; //设置鼠标形状 this.pb.Cursor = Cursors.Cross; } public void DrawLine(Point ps, Point pd) { //擦除之前画的线 dgGraphic.DrawLine(new Pen(this.pb.BackColor), ps, preP); dgGraphic.Clear(this.pb.BackColor); Pen p = palette.CurrentPen; p.Width = 3; dgGraphic.DrawLine(p, ps, pd); this.pb.Image = p_bmp; preP = pd; } ~DrawBoard() { if (dgGraphic != null) dgGraphic.Dispose(); } } }
调色板类实现:
调色板聚合了颜色管理器,主要负责通过配置文件Colors.xml初始化颜色管理器,并在PictureBox呈现配置的颜色。用户可以选择相应的颜色,在画板中画出来。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; using PrototypePattern.Color; using System.Xml; using System.Collections; namespace PrototypePattern.Draw { /// <summary> /// 调色板类 /// </summary> public class Palette { private PictureBox pb; private Bitmap p_bmp; private Graphics dgGraphic;//画布 private ColorManager colorsM=new ColorManager();//颜色管理器,用于管理封装的颜色对象聚集 private Dictionary<string, Point> color_positions = new Dictionary<string, Point>();//存储颜色在调色板中的位置,该坐标为判断当前是否选中某种颜色使用。在初始化颜色聚集的时候,保存颜色初始位置。 public int Width //颜色块的配置宽度 { get; set; } public int Height //颜色块的配置高度 { get; set; } public Palette(ref PictureBox p) { this.pb = p; p_bmp = new Bitmap(this.pb.Width, this.pb.Height); dgGraphic =Graphics.FromImage(p_bmp); this.pb.Image = p_bmp; colorsM = new ColorManager(); //设置鼠标形状 this.pb.Cursor = Cursors.Hand; } /// <summary> /// 初始化调色板(通过读取颜色配置文件Colors.xml初始化) /// </summary> /// <param name="filename"></param> /// <returns></returns> public bool InitializePalette(string filename) { try { XmlDocument xdoc = new XmlDocument(); xdoc.Load(filename); XmlNodeList xlst= xdoc.GetElementsByTagName("color"); Width = Convert.ToInt32(xdoc.SelectSingleNode("/Colors/width").InnerText); Height = Convert.ToInt32(xdoc.SelectSingleNode("/Colors/height").InnerText); foreach (XmlNode xn in xlst) { XmlElement element = (XmlElement)xn; int r=Convert.ToInt32(element.SelectSingleNode("r").InnerText); int g=Convert.ToInt32(element.SelectSingleNode("g").InnerText); int b=Convert.ToInt32(element.SelectSingleNode("b").InnerText); colorsM[element.GetAttribute("name")]=new ConcreteColorPrototype(r,g,b).Clone();//通过克隆生成具体颜色对象,并由颜色管理器管理 } return true; } catch { throw new Exception("初始化调色板出错!"); } } /// <summary> /// 绘制调色板 /// </summary> public void Draw() { int p_width=this.pb.Width; int n = this.pb.Width / (Width + 2); int i = 0; int p_x = this.pb.Location.X, p_y = this.pb.Location.Y; int x = 0, y = 0; dgGraphic.Clear(this.pb.BackColor);
//根据颜色管理器管理的颜色聚集,在调色板上绘制一个个颜色正方形 while (colorsM.MoveNext()) { y = i / n; x = i % n; int w=x * (Width + 2); int h=y * (Height + 2); color_positions.Add(colorsM.CurrentColor, new Point(w, h)); dgGraphic.FillRectangle(colorsM.Current, new Rectangle(w+5,h+5, Width, Height)); i++; } Point originP = color_positions[colorsM.CurrentColor]; dgGraphic.DrawRectangle(new Pen(Brushes.DeepPink, 1), originP.X - 1 + 5, originP.Y - 1 + 5, Width + 1, Height + 1); } /// <summary> /// 选中调色板颜色 /// </summary> /// <param name="p"></param> public void SelectColor(Point p) { Point originP = color_positions[colorsM.CurrentColor]; dgGraphic.DrawRectangle(new Pen(this.pb.BackColor,1), originP.X - 1+5, originP.Y - 1+5, Width + 1, Height + 1); foreach (KeyValuePair<string, Point> kv in color_positions) {
//当用户单击颜色板时,通过鼠标当前坐标是否选中某种颜色,若在某种颜色方块颜色范围内就绘制选中的框,用于区别当前哪种颜色被选中 if(p.X>=kv.Value.X&&p.Y>=kv.Value.Y&&p.X<=(kv.Value.X+32)&&p.Y<=(kv.Value.Y+32)) { colorsM.CurrentColor = kv.Key; dgGraphic.DrawRectangle(new Pen(Brushes.DeepPink, 1), kv.Value.X - 1 + 5, kv.Value.Y - 1 + 5, Width + 1, Height + 1); pb.Image = p_bmp; break; } } } /// <summary> /// 返回当前画笔 /// </summary> public Pen CurrentPen { get {
//根据颜色管理器当前颜色,生成画笔返回供画板划线使用 ConcreteColorPrototype ccp=colorsM[colorsM.CurrentColor] as ConcreteColorPrototype; return new Pen(System.Drawing.Color.FromArgb(ccp.Red, ccp.Green, ccp.Blue)); } } ~Palette() { if (dgGraphic != null) dgGraphic.Dispose(); } } }
颜色管理器实现:
颜色管理器的功能顾名思义就是管理颜色的,它封装了配置的颜色,并记录当前颜色,相关实现如下,欢迎大家提出意见!
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Drawing; namespace PrototypePattern.Color { public class ColorManager {
//用于存储颜色聚集 private Hashtable colors = new Hashtable(); //保存当前颜色名 private string currentColor; private string originColor; private int index=-1; private List<string> keys=new List<string>(); public List<string> Keys { get { return keys; } } //给颜色聚集增加索引器 public ColorPrototype this[string name] { get { return colors[name] as ColorPrototype; } set { if (colors.Count == 0) { CurrentColor = name; originColor = name; } Keys.Add(name); colors.Add(name, value); } } public string CurrentColor { get { return currentColor; } set { currentColor = value; } } public Brush Current { get {
//返回当前颜色块画刷 ConcreteColorPrototype ccp=this[Keys[index]] as ConcreteColorPrototype; SolidBrush sb = new SolidBrush(System.Drawing.Color.FromArgb(ccp.Red, ccp.Green, ccp.Blue)); return sb; } } public bool MoveNext() { int len = Keys.Count; index++; if (index > len - 1) return false; currentColor = Keys[index]; return true; } public void Reset() { index = Keys.FindIndex(p => p == originColor); } } }
颜色原型实现:
颜色原型提供了克隆的接口
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace PrototypePattern.Color {
//抽象颜色原型 public abstract class ColorPrototype { public abstract ColorPrototype Clone(); } }
具体颜色类实现:
具体颜色对象封装了颜色分量,通过克隆产生具体颜色对象(这里是浅复制,深复制见引用博客网址)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace PrototypePattern.Color {
//具体颜色原型 public class ConcreteColorPrototype:ColorPrototype { private int _red, _green, _blue; public int Red { get { return _red; } } public int Green { get { return _green; } } public int Blue { get { return _blue; } } public ConcreteColorPrototype(int red, int green, int blue) { this._red = red; this._green = green; this._blue = blue; } public override ColorPrototype Clone() { return this.MemberwiseClone() as ColorPrototype; } } }
Winform实现:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using PrototypePattern.Draw; namespace PrototypePattern { public partial class Form1 : Form { Palette p; DrawBoard db; bool isDraw = false; Point p_s;//画图起始点 public Form1() { InitializeComponent(); //设置调色板,并绘制在窗口上 p = new Palette(ref pb_palette); p.InitializePalette("Colors.xml"); p.Draw(); //初始化画板 db = new DrawBoard(ref pb_board, ref p); } private void pb_palette_MouseClick(object sender, MouseEventArgs e) { p.SelectColor(new Point(e.X, e.Y)); } private void pb_board_MouseDown(object sender, MouseEventArgs e) { isDraw = true; p_s = new Point(e.X, e.Y); } private void pb_board_MouseMove(object sender, MouseEventArgs e) { if(isDraw) db.DrawLine(p_s, new Point(e.X, e.Y)); } private void pb_board_MouseUp(object sender, MouseEventArgs e) { if (isDraw) { db.DrawLine(p_s, new Point(e.X, e.Y)); isDraw = false; } } private void Form1_Load(object sender, EventArgs e) { } } }
Colors.xml结构:
<?xml version="1.0" encoding="utf-8" ?> <Colors> <width> 32 </width> <height> 32 </height> <color name="red"> <r>255</r> <g>0</g> <b>0</b> </color> <color name="green"> <r>0</r> <g>255</g> <b>0</b> </color> <color name="blue"> <r>0</r> <g>0</g> <b>255</b> </color> <color name="purple"> <r>108</r> <g>51</g> <b>101</b> </color> <color name="orange"> <r>255</r> <g>160</g> <b>66</b> </color> <color name="black"> <r>0</r> <g>0</g> <b>0</b> </color> </Colors>
实现效果:
原型模式参考网址:http://terrylee.cnblogs.com/archive/2006/01/16/317896.html