- 创建型模式
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 分类
- 工厂模式(Factory Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
- 单例模式(Singleton Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
- 工厂模式(Factory Pattern)
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
C#: public abstract class Product //抽象产品类
{
public abstract void method(); //抽象方法
}
public class ConcreteProduct:Product //具体产品类
{
public override void method()
{
//业务逻辑处理
}
}
public class Factory //工厂类
{
//根据类名创建对象
public Product GetProduct(String name)
{
if (name.Equals("ConcreteProduct", StringComparison.CurrentCultureIgnoreCase)) return new ConcreteProduct();
return null;
}
//根据类型创建对象
public static Product getProduct(Type type)
{
//判断type是否继承了Shape接口
if (typeof(Product).IsAssignableFrom(type))
return (Product)Activator.CreateInstance(type);
return null;
}
}
public class Client //场景类
{
public static void Main(string[] args)
{
Factory factory = new Factory();
Product p1 = factory.GetProduct("concreteproduct");
Product p2 = Factory.getProduct(typeof(ConcreteProduct));
}
}
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
- 抽象工厂模式(Abstract Factory Pattern)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
public interface IProduct
{
public void method1();
}
public abstract class AbstractProduct1:IProduct
{
public abstract void method2();
}
public abstract class AbstractProduct2 : IProduct
{
public abstract void method2();
}
public class ConcreteProduct1 : AbstractProduct1
{
public override void method2()
{
//业务逻辑处理
}
public void method1()
{
//业务逻辑处理
}
}
public class ConcreteProduct2 : AbstractProduct2
{
public override void method2()
{
//业务逻辑处理
}
public void method1()
{
//业务逻辑处理
}
}
public abstract class AbstractFactory
{
//有几个产品簇的工厂就有几个实现方法
public abstract AbstractProduct1 GetProduct1(string name);
public abstract AbstractProduct2 GetProduct2(string name);
}
public class Factory1:AbstractFactory
{
//根据类名创建对象
public override AbstractProduct1 GetProduct1(String name)
{
if (name.Equals("ConcreteProduct1", StringComparison.CurrentCultureIgnoreCase)) return new ConcreteProduct1();
return null;
}
}
public class Factory2 : AbstractFactory
{
//根据类名创建对象
public override AbstractProduct2 GetProduct2(String name)
{
if (name.Equals("ConcreteProduct2", StringComparison.CurrentCultureIgnoreCase)) return new ConcreteProduct2();
return null;
}
}
public class FactoryCreator //创建工厂的类
{
//根据类名创建对象
public static AbstractFactory GetFactory(String name)
{
if (name.Equals("Factory1", StringComparison.CurrentCultureIgnoreCase)) return new Factory1();
if (name.Equals("Factory2", StringComparison.CurrentCultureIgnoreCase)) return new Factory2();
return null;
}
}
public class Client
{
public static void Main(string[] args)
{
//AbstractFactory factory1 = new Factory1();
//AbstractFactory factory2 = new Factory2();
AbstractFactory factory1 = FactoryCreator.GetFactory("Factory1");
AbstractFactory factory2 = FactoryCreator.GetFactory("Factory2");
ConcreteProduct1 p1 = factory1.GetProduct1("concreteproduct1") as ConcreteProduct1;
ConcreteProduct2 p2 = factory2.GetProduct2("concreteproduct2") as ConcreteProduct2;
}
}
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
注意事项:产品族难扩展(改动太大,不符合开闭原则),产品等级易扩展。
- 单例模式(Singleton Pattern)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
c# public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton Instance
{
get
{
return instance;
}
}
public void ShowMessage()
{
Console.WriteLine("this is a singleObject");
}
}
public class Client
{
static void Main(string[] args)
{
Singleton.Instance.ShowMessage();
}
}
优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。当前是线程不安全的。
- 建造者模式(Builder Pattern)
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
public class Product
{
public void doSomething()
{
//独立业务处理
}
}
public abstract class Builder
{
public abstract void setPart();//设置产品的不同部分,以获得新的产品
public abstract Product buildProduct();//建造产品
}
public class ConcreteBuilder:Builder
{
private Product product = new Product();
//设置产品零件
public override void setPart()
{
//产品类内的逻辑处理
}
//组建一个产品
public override Product buildProduct()
{
return product;
}
}
public class Director
{
private Builder builder = new ConcreteBuilder();
//构建不同的产品
public Product getAProduct()
{
builder.setPart();
//设置不同的零件,产生不同的产品
return builder.buildProduct();
}
}
public class Client
{
static void Main(string[] args)
{
Director director = new Director();
Product product = director.getAProduct();
}
}
优点: 1、建造者独立,易扩展。
2、便于控制细节风险。
缺点: 1、产品必须有共同点,范围有限制。
2、如内部变化复杂,会有很多的建造类。
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。
注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。与模版方法模式结合使用更佳(产品类中使用模版方法)
- 原型模式(Prototype Pattern)
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
public class Client
{
static void Main(string[] args)
{
Prototype pt1 = new Prototype();
Prototype pt2 = (Prototype)pt1.Clone();
Console.WriteLine(pt2.name);
}
}
public class Prototype : ICloneable //实现接口
{
public string name = "ssss";
public object Clone()
{
object obj = null;
try
{
obj = this.MemberwiseClone();//浅拷贝
}
catch (Exception e)
{
Console.WriteLine(e.Message);
//异常处理
}
return obj;
}
}
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 ICloneable 接口。
使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 ICloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。