Ø 原型模式
定义:原型模式(Prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
以简历(Resume)复印为例。程序代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Resume:ICloneable
{
private string name;
private string sex;
private string age;
private string timeArea;
private string company;
public Resume(string name)
{
this.name = name;
}
//设置个人信息
public void SetPersonalInfo(string sex, string age)
{
this.sex = sex;
this.age = age;
}
//设置工作经历
public void SetWorkExperience(string timeArea, string company)
{
this.timeArea = timeArea;
this.company = company;
}
//显示
public void Display()
{
Console.WriteLine("{0}{1}{2}", name, sex, age);
Console.WriteLine("工作经历:{0}{1}", timeArea, company);
}
public Object Clone()
{
return (Object)this.MemberwiseClone();
}
}
}
客户端
static void Main(string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男", "29");
a.SetWorkExperience("1998-2000", "xx公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("1998-2006", "YY公司");
Resume c = (Resume)a.Clone();
a.SetPersonalInfo("男", "24");
a.Display();
b.Display();
c.Display();
Console.Read();
}
u 注意的地方
l .NET在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),实现这个接口就可以完成原型模型了。
l 一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这样即隐藏了对象创建的细节,又对性能是大大的提高。
l 不用重新初始化对象,而是动态地获得对象运行时的状态。
l MemberwiseClone()为浅表复制,对于值类型,没有什么问题但是对于引用类型,只是复制了引用,对于引用的对象还是指向了原来的对象。(即涉及到深浅复制,下一篇将讲)
Ø 模板方法模式
定义:模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
模板方法模式就是把不变的行为搬移到超类,去除子类中重复代码来体现它的优势。也就是说当可变的或者不可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现,这样通过模板方法模式可以把这些行为搬移到单一的地方,从而帮助子类摆脱重复的不变行为的纠缠。
简而言之,它提供了一个很好的代码复用平台。
以试卷代码为例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication9
{
class TestPaper
{
public void TestQuestion1()
{
Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙宝刀的玄铁可能是[]a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维");
Console.WriteLine("答案:" + Answer1());
}
protected virtual string Answer1()
{
return "";
}
public void TestQuestion2()
{
Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙宝刀的玄铁可能是[]a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维");
Console.WriteLine("答案:" + Answer2());
}
protected virtual string Answer2()
{
return "";
}
public void TestQuestion3()
{
Console.WriteLine("杨过得到,后来给了郭靖,炼成倚天剑、屠龙宝刀的玄铁可能是[]a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维");
Console.WriteLine("答案:" + Answer3());
}
protected virtual string Answer3()
{
return "";
}
}
class TestPaperA : TestPaper
{
protected override string Answer1()
{
return "b";
}
protected override string Answer2()
{
return "c";
}
protected override string Answer3()
{
return "a";
}
}
class TestPaperB : TestPaper
{
protected override string Answer1()
{
return "b";
}
protected override string Answer2()
{
return "a";
}
protected override string Answer3()
{
return "a";
}
}
}
客户端代码
static void Main(string[] args)
{
Console.WriteLine("学生甲抄的试卷");
TestPaper studentA = new TestPaperA();
studentA.TestQuestion1();
studentA.TestQuestion2();
studentA.TestQuestion3();
Console.WriteLine("学生乙抄的试卷");
TestPaper studentB=new TestPaperB ();
studentB .TestQuestion1 ();
studentB .TestQuestion2 ();
studentB .TestQuestion3 ();
Console.Read ();
}
我们可以看到试卷的内容是一样的,只有答案是不同,因为不同学生答案不同。那我们就可以把答案抽象出一个虚的方法,在子类中延期实现。
Ø 区别与联系
联系:把问题放到一个地方,提供一个代码复用的平台,把变化的和不变的东西分离开,来实现某种需求。
区别:原型模型意在通过拷贝,或者说复印,以期在客户端最小的代码修改量,来实现自己的目的。
而模板方法模式是封装不变的,扩展可变的,把可变的与不可变的行为分离开来,从而使得代码可以更好地使用。
这时不免想到建造者模式,把建造代码与表示代码分离,建造者隐藏了内部建造的细节,若是需要改变一个产品内部,只需定义一个具体的建造者即可。这也是增强了代码的复用性,这样也使得代码易被使用。