创建型设计模式:
创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)定义一个用于创建对象的接口,让子类决定实例化哪个类。Factory Method使一个类的实例化延迟到其子类。
- 抽象工厂模式(Abstract Factory)提供一个创建一系列或互相依赖对象的接口,而无需指定它们具体的类。
- 建造者模式(Builder)将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。
- 原型模式(Prototype)用原型实例指定创建对象的种类,并且通过复制这些原创创建新的对象。
- 单例模式(Singleton)保证一个类仅有一个实例,并提供一个全局访问点。
简单工厂模式
功能:主要用于创建对象。新添加类时,不会影响以前的系统代码。核心思想是用一个工厂来根据输入的条件产生不同的类,然后根据不同类的virtual函数得到不同的结果。
优点: 适用于不同情况创建不同的类时
缺点: 客户端必须要知道基类和工厂类,耦合性差
模式结构:
Factory:工厂角色负责实现创建所有实例的内部逻辑
Product:抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
ConcreteProduct:具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
简单工厂模式实现程序
//运算类
class OPeration
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
double result = 0;
return result;
}
}
//加减乘除类
class OperationAdd : Operation //加法类
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
class OperationSub : Operation //减法类
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
class OpertionMul : Operation //乘法类
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
class OperationDiv : Operation //除法类
{
public override double GetResult()
{
double result = 0;
if (NumberB==0)
{
throw new Exception("除数不能为0");
}
result = NumberA / NumberB;
return result;
}
}
//简单运算工厂类
public class OperationFactory
{
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OpertionMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
//客户端代码
class Program
{
public static void Main(string[] args)
{
Operation oper;
oper = OperationFactory.createOperate("-");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
Console.WriteLine(result);
Console.ReadLine();
}
}
工厂方法模式(多态工厂模式)
功能:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
优点:
向客户隐藏了哪种具体产品将被实例化的细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,无须知道具体产品类的类名。
基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
系统中加新产品时,无须修改抽象工厂和抽象产品的接口,(但要修改客户端,以选择不同的具体工厂!),无须修改其他的具体工厂和产品,而只要添加一个具体工厂和具体产品即可。符合“开闭原则”。
缺点:
在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
工厂方法模式实现程序
//雷锋类
class LeiFeng
{
public void Sweep()
{
Console.WriteLine("扫地");
}
public void Wash()
{
Console.WriteLine("洗衣");
}
public void BuyRice()
{
Console.WriteLine("买米");
}
}
//学雷锋的大学生类
class Undergraduate : LeiFeng
{
}
//社区志愿者
class Volunteer : LeiFeng
{
}
//雷锋工厂
interface IFactory
{
LeiFeng CreateLeiFeng();
}
//学雷锋的大学生工厂
class UndergraduateFactory : IFactory
{
public LeiFeng CreateLeiFeng()
{
return new Undergraduate();
}
}
//社区志愿者工厂
class VolunteerFactory : IFactory
{
public LeiFeng CreateLeiFeng()
{
return new Volunteer();
}
}
//客户端
class Program
{
static void Main(string[] args)
{
//工厂方法模式
IFactory factory = new UndergraduateFactory();
LeiFeng student = factory.CreateLeiFeng();
student.BuyRice();
student.Sweep();
student.Wash();
Console.Read();
}
}
抽象工厂模式(Kit模式)
功能:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
优点:
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,此模式可以实现高内聚低耦合的设计目的。
当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,很实用。
增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点:
在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。
抽象工厂模式实现程序
//用户表
class User
{
private int _id;
private int ID
{
get { return _id; }
set { _id = value;}
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
//SqlserverUser类 用于访问SQLServer的User
class SqlserverUser : IUser
{
public void Insert(User user)
{
Console.WriteLine("在SQLServer中根据ID得到User表一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在SQLServer中根据id得到User表一条记录");
return null;
}
}
//IUser接口 用于客户端的访问,解除与具体数据库访问的耦合
interface IUser
{
void Insert(User user);
User GetUser(int id);
}
//AccessUser类 用于访问Access的User
class AccessUser : IUser
{
public void Insert(User user)
{
Console.WriteLine("在Access中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在Access中根据ID得到User表一条记录");
return null;
}
}
//抽象工厂接口 定义一个创建访问User表对象的抽象工厂接口+Department
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();
}
//SqlServerFactory类 实现IFactory接口,实例化SqlserverUser和SqlserverDepartment
class SqlServerFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
//AccessFactory类 实现IFactory接口,实例化AccessUser和AccessDepartment
class AccessFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
}
//部门表
class Department
{
private int _id;
private int ID
{
get { return _id; }
set { _id = value; }
}
private string _deptName;
public string DeptName
{
get { return _deptName; }
set { _deptName = value; }
}
}
//IDepartment接口 用于客户端访问,解除与具体数据库访问的耦合
interface IDepartment
{
void Insert(Department department);
Department GetDepartment(int id);
}
//SqlserverDepartment类 用于访问SQLServer的Department
class SqlserverDepartment : IDepartment
{
public void Insert(Department department)
{
Console.WriteLine("在SQLServer中给Department表增加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在SQLServer中根据ID得到Department表一条记录");
return null;
}
}
//AccessDepartment类 用于访问Access的Department
class AccessDepartment : IDepartment
{
public void Insert(Department department)
{
Console.WriteLine("在Access中给Department表增加一条记录");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在Access中根据ID得到Department表一条记录");
return null;
}
}
//抽象工厂接口 定义一个创建访问User表对象的抽象工厂接口+Department
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();
}
//SqlServerFactory类 实现IFactory接口,实例化SqlserverUser和SqlserverDepartment
class SqlServerFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
//AccessFactory类 实现IFactory接口,实例化AccessUser和AccessDepartment
class AccessFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
}
//客户端
class Program
{
static void Main(string[] args)
{
User user = new User();
Department dept = new Department();
//IFactory factory = new SqlServerFactory();
IFactory factory = new AccessFactory();
IUser iu = factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = factory.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
Console.Read();
}
}
建造者模式(生成器模式)
功能:
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
优点:
客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
每一个具体建造者都独立,因此可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭”。
缺点:
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,若产品之间的差异性很大,则不适合使用该模式,因此其使用范围受到一定限制。
若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
建造者模式实现程序
//建造人的类
abstract class PersonBuilder
{
protected Graphics g;
protected Pen p;
public PersonBuilder(Graphics g, Pen p)
{
this.g = g;
this.p = p;
}
public abstract void BuildHead();
public abstract void BuildBody();
public abstract void BuildArmLeft();
public abstract void BuildArmRight();
public abstract void BuildLegLeft();
public abstract void BuildLegRight();
}
//瘦子类
class PersonThinBuilder : PersonBuilder
{
public PersonThinBuilder(Graphics g, Pen p) : base(g, p)
{ }
public override void BuildHead()
{
g.DrawEllipse(p, 50, 20, 30, 30);
}
public override void BuildBody()
{
g.DrawRectangle(p, 60, 50, 10, 50);
}
public override void BuildArmLeft()
{
g.DrawLine(p, 60, 50, 40, 100);
}
public override void BuildArmRight()
{
g.DrawLine(p, 70, 50, 90, 100);
}
public override void BuildLegLeft()
{
g.DrawLine(p, 60, 100, 45, 150);
}
public override void BuildLegRight()
{
g.DrawLine(p, 70, 100, 85, 150);
}
}
//指挥者类
class PersonDirector
{
private PersonBuilder pb;
public PersonDirector(PersonBuilder pb)
{
this.pb = pb;
}
public void CreatePerson()
{
pb.BuildHead();
pb.BuildBody();
pb.BuildArmLeft();
pb.BuildArmRight();
pb.BuildLegLeft();
pb.BuildLegRight();
}
}
//图片框的单击事件
private void pictureBox1_Click(object sender, EventArgs e)
{
Pen p = new Pen(Color.Red);
PersonThinBuilder pfb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p);
PersonDirector pdThin = new PersonDirector(pfb);
pdThin.CreatePerson();
Console.Read();
}
单例模式
功能:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
优点:
提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
缺点:
由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
单例模式实现程序
//Form1窗体
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private FormToolbox ftb;
private void toolStripMenuItemToolboxToolStripMenuItem_Click(object sender, EventArgs e)
{
FormToolbox.GetInstance().Show();
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
FormToolbox.GetInstance().Show();
}
private void Form1_Load(object sender, EventArgs e)
{
this.IsMdiContainer = true;
}
}
//FormToolbox窗体
public partial class FormToolbox : Form
{
private static FormToolbox ftb = null;
private FormToolbox()
{
InitializeComponent();
}
public static FormToolbox GetInstance()
{
if (ftb == null || ftb.IsDisposed)
{
ftb = new FormToolbox();
ftb.MdiParent = Form1.ActiveForm;
}
return ftb;
}
private void FormToolbox_Load(object sender, EventArgs e)
{
}
}
原型模式
功能:
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象创建另外一个可定制的对象,而且不需知道任何创建的细节。
优点:
一般在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建细节,又提高性能。其等于是不用重新初始化对象,而是动态地获得对象运行时的状态。
原型模式实现程序
//工作经历类
class WorkExperience : ICloneable
{
private string workDate;
public string WorkDate
{
get { return workDate; }
set { workDate = value; }
}
private string company;
public string Company
{
get { return company; }
set { company = value; }
}
public Object Clone()
{
return (object)this.MemberwiseClone();
}
}
//简历类
class Resume : ICloneable
{
private string name;
private string sex;
private string age;
private WorkExperience work;
public Resume(string name)
{
this.name = name;
work = new WorkExperience();
}
private Resume(WorkExperience work)
{
this.work = (WorkExperience)work.Clone();
}
//设置个人信息
public void SetPersonalInfo(string sex, string age)
{
this.sex = sex;
this.age = age;
}
//设置工作经历
public void SetWorkExperience(string workDate, string company)
{
work.WorkDate = workDate;
work.Company = company;
}
//显示
public void Display()
{
Console.WriteLine(" {0} {1} {2}", name, sex, age);
Console.WriteLine("工作经历: {0} {1}", work.WorkDate, work.Company);
}
public Object Clone()
{
Resume obj = new Resume(this.work);
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age;
return obj;
}
}
//客户端代码
class Program
{
static void Main(string[] args)
{
Resume a = new Resume("大鸟");
a.SetPersonalInfo("男", "29");
a.SetWorkExperience("1998-2000", "xx公司");
Resume b = (Resume)a.Clone();
b.SetWorkExperience("2000-2009", "yy公司");
Resume c = (Resume)a.Clone();
c.SetWorkExperience("2009-2018", "zz企业");
a.Display();
b.Display();
c.Display();
Console.Read();
}
}