c#设计模式之装饰者模式
装饰者模式是动态地扩展一个对象的功能。下面看一个例子:网页中要使用图片,我要上传图片,具体规则:
1、对于一些比较大,甚至几兆的图片,上传后,生成缩略图,生成缩略图可以按照指定尺寸,或者固定宽,高按比例缩放。
2、对于tif格式的图片,通常都比较大,需要转jpg格式的图片,或者转jpg格式后,若发现图片还是很大,再进行压缩处理。
3、对于合适大小的图片,上传上去不做处理。
首先定义一个抽象类,用来实现上传:
1 public abstract class AbstractUpload 2 { 3 4 public Stream FileStream { set; get; } 5 6 7 public UploadInfo Result { set; get; } 8 9 public abstract byte[] GetContent(); 10 11 public virtual UploadInfo Upload(string listTitle, string fileName, bool isRename = true){ 12 //具体上传方法 13 } 14 public virtual UploadInfo GetResult(){ 15 16 //获取上传结果 17 } 18 }
然后定义装饰者的抽象类:
1 public abstract class UploadDecrator:AbstractUpload 2 { 3 public AbstractUpload UpLoader { set; get; } 4 5 }
下面是按照规定尺寸生成缩略图:
public class ThumbUpload:UploadDecrator { public ThumbImageInfo ImgInfo { set; get; } public ThumbUpload(AbstractUpload upload,ThumbImageInfo imgInfo) { this.UpLoader = upload; this.ImgInfo = imgInfo; } public override byte[] GetContent() { var img= MakeSmallPic(); return StringUlity.ImgToByte(img); } }
接着,我们实现tif图片的处理:
1 public class TifImageUpload : UploadDecrator 2 { 3 public ThumbImageInfo ImgInfo { set; get; } 4 5 public bool IsCacularMode { set; get; } 6 7 public TifImageUpload(AbstractUpload upload, ThumbImageInfo imgInfo, bool isCacularMode) 8 { 9 10 this.UpLoader = upload; 11 12 this.ImgInfo = imgInfo; 13 14 this.IsCacularMode = isCacularMode; 15 } 16 17 public TifImageUpload(AbstractUpload upload, bool isCacularMode) 18 { 19 20 this.UpLoader = upload; 21 this.IsCacularMode = isCacularMode; 22 } 23 24 25 public override byte[] GetContent() 26 { 27 var img = MakeSmallPic(); 28 29 return StringUlity.ImgToByte(img); 30 } 31 }
看到这儿,可能有人会有疑问,具体的类,为什么不直接继承AbstractUpload呢?因为AbstractUpload类是一个抽象类,它还为其它的各种文件上传使用,为了不影响这个基础的抽象类,所以我们单独定义自己的装饰者抽象类。
看看客户端是如何调用的?
这个是上传tif图片,处理为jpg格式,然后再上传。
看到这里,是不是觉得FileStreamUpload f ,这个有点问题,与构造函数的类型不一致呢?且看下文:
1 /// <summary> 2 /// 上传文件 3 /// </summary> 4 public class FileStreamUpload : AbstractUpload 5 { 6 7 public FileStreamUpload(Stream stream) 8 { 9 10 this.FileStream = stream; 11 } 12 13 public override byte[] GetContent() 14 { 15 int iLength = (int)FileStream.Length; 16 17 18 Byte[] filecontent=null; 19 20 if (iLength > 0) 21 { 22 filecontent = new byte[iLength]; 23 FileStream.Read(filecontent, 0, iLength); 24 } 25 return filecontent; 26 } 27 }
这个是所有文件上传类,也继承自抽象类AbstractUpload。且看这些类之间的关系:
上图是装饰者模式的uml图,其巧妙之处在于装饰者类UploadDecrator组合了自己的一个基类。这是一个组合优于继承的设计原则体现。说到这儿,我们回顾下面向对象设计的基本原则:
1、单一职责:一个类只做一件事情。
2、开闭原则:对修改关闭,对扩展开放。
3、依赖倒置:高层模块不应该依赖于低层模块,两者均依赖于抽象。这个抽象是从高层模块抽象出来的。
4、里氏替换:子类可以替换父类,可以在运行时决定是哪个子类替代父类实现,它是实现开闭原则的重要方式。
5、接口隔离:尽量使用“瘦”接口。
6、迪米特法则:最少知识原则,一个对象对其它对象有尽可能少的了解。
7、组合/聚合复用原则:组合优于继承。
前5个为基本原则。设计模式会体现这些设计原则,所以我们必须得好好参悟。