最常用的设计模式根据我的经验我把我经常用到的设计模式在这里做个总结,按照我的经验,它们的排序如下:1)单件模式、2)抽象工厂模式和工厂模式、3)适配器模式、4)装饰模式、5)观察者模式、6)外观模式 其他模式目前还很少用到。
单件模式
这是用的最多的模式,每一个正式的软件都要用它,全局配置、唯一资源、还有一个就是所有的工厂我都设计为单件模式,因此它的使用量大于工厂模式和抽象工厂模式之和。是用来创建一个需要全局唯一实例的模式。只是需要纠正一点。singleton模式中,构造函数应该是protected.这样子类才可以扩展这个构造函数。
单件模式主要应用在以下场合:
1. 对于一个类,占用的系统资源非常多。而且这些资源可以被全局共享,则可以设计为singleton模式,强迫全局只有一个实例
2. 对于一个类,需要对实例进行计数。可以在createInstance中进行并可以对实例的个数进行限制。
3. 对于一个类,需要对其实例的具体行为进行控制,例如,期望返回的实例实际上是自己子类的实例。这样可以通过Singleton模式,对客户端代码保持透明。
Singleton模式是一个较为简单的模式,下面的代码就可以建立一个Singlton模式的例子,这是一个写系统日志的类,实际应用的意义在于在内存中只保存一个实例,避免开辟多个功能相同的工具类实例而耗用系统资源。当多个应用调用同一个工具类或控制类时特别有意义,建议团队开发时采用。
public class LogWriter
{
//申明一个静态的变量,类型为类本身
private static LogWriter _instance = null;
//将类的构造函数私有化,使得这个类不可以被外界创建
private LogWriter()
{
}
//提供静态的方法,创建类的实例
public static LogWriter GetInstance()
{
if (_instance == null)
{
_instance = new LogWriter();
}
return _instance;
}
}
分析:如果是多线程的情况下该如何保持单件模式?
A: 多线程时应该也是单件的吧,因为线程之间是共享内存的。
请问要是我想限制实例个数不超过10个 应该怎么办呢?
A: 做个类似线程池的东西吧
多线程下面也可以用,可以有很多种方法
1、对静态方法进行同步,2、急切创建实例,3、双重检查加锁
public class Singleton {
private volatile static Singleton singleton ;
private Singleton () {}
public Singleton ( String name ) {}
public static Singleton getInstance () {
if ( singleton == null ) {
synchronized ( Singleton.class ) {
if ( singleton == null ) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
单例模式:单例的实现和上面模式演变中的最后一种很相似,只要把构造器私有便OK。
简单工厂模式
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
public class SteamedBread
{
public SteamedBread() // 构造方法
{ }
private double price=0.5;
public double Price
{
get { return price; }
set { price = value; }
}
}
OK,产品对象建立好了,下面就是创建工厂(Factory)对象了。
public class Factory
{
public static SteamedBread CreateInstance() // 创建一个馒头(SteamedBread)对象
{
return new SteamedBread();
}
}
此时,客户端可以这样来调用:
public class Client
{
public static void Main(string[] args)
{
//通过工厂创建一个产品的实例
SteamedBread sb = Factory.CreateInstance();
Console.WriteLine("馒头{0}元一个!", sb.Price);
}
}
工厂模式
public interface IFruit
{
}
public class Orange:IFruit
{
public Orange()
{
Console.WriteLine("An orange is got!");
}
}
public class Apple:IFruit
{
public Apple()
{
Console.WriteLine("An apple is got!");
}
}
我们的FruitFactory应该是怎么样呢?上面的结构图中它给的是CreateProductA,那好,我就MakeOrange,还有一个CreateProductB,俺MakeOrange还不行??
public class FruitFactory
{
public Orange MakeOrange()
{
return new Orange();
}
public Apple MakeApple()
{
return new Apple();
}
}
怎么使用这个工厂呢?我们来写下面的代码:
string FruitName = Console.ReadLine();
IFruit MyFruit = null;
FruitFactory MyFruitFactory = new FruitFactory();
switch (FruitName)
{
case "Orange":
MyFruit = MyFruitFactory.MakeOrange();
break;
case "Apple":
MyFruit = MyFruitFactory.MakeApple();
break;
default:
break;
}
抽象工厂模式
示意性代码如下:
/// <summary>
/// 食品接口----扮演抽象产品角色
/// </summary>
public interface IFood
{
/// <summary>
/// 每种食品都有销售价格,这里应该作为共性提升到父类或是接口来
/// 由于我们只需要得到价格,所以这里就只提供get属性访问器
/// </summary>
double price{get;}
}
------------------------------------------------------------------------------------
/// <summary>
/// 馒头
/// </summary>
public class SteamedBread:IFood
{
/// <summary>
/// 构造方法
/// </summary>
public SteamedBread()
{ }
public double price
{
get
{
return 0.5;
}
}
}
------------------------------------------------------------------------------------
/// <summary>
/// 包子
/// </summary>
public class SteamedStuffed:IFood
{
public SteamedStuffed()
{ }
/// <summary>
/// 销售价格
/// </summary>
public double price
{
get
{
return 0.6; //0.6元一个
}
}
}
------------------------------------------------------------------------------------
/// <summary>
/// 工厂角色
/// </summary>
public class Factory
{
/// <summary>
/// 创建一个馒头(SteamedBread)对象
/// </summary>
/// <returns></returns>
public static IFood CreateInstance(string key)
{
if (key == "馒头")
{
return new SteamedBread();
}
else
{
return new SteamedStuffed();
}
}
}
------------------------------------------------------------------------------------
public class Client
{
public static void Main(string[] args)
{
//通过工厂创建一个产品的实例
IFood food = Factory.CreateInstance("馒头");
Console.WriteLine("馒头{0}元一个!", food.price);
food = Factory.CreateInstance("包子");
Console.WriteLine("包子{0}元一个!", food.price);
}
}
此时的设计就已经完全符合简单工厂模式的意图了。顾客(Client)对早餐店营业员(Factory)说,我要“馒头”,于是营业员便根据顾客所提供的数据(馒头),去众多食品中找,找到了然后就拿给顾客。
其他模式
适配器模式
配器模式有两种类的适配器和对象适配器,对象适配器更多一些,对象适配器的优点在很多大侠的著作了已经论述n次了,我这里不多啰嗦,我用的较多的原因还有一个,我从C++转到C#,由于C#不支持多重继承,我又不比较懒,较少定义interface,因此大多数情况下用C#时也只能使用对象适配器模式了。其实适配器和装饰模式功能上有很大的相似性,在下面的装饰模式中加以论述。
装饰模式
也叫油漆工模式,装饰模式和适配器模式相似都是用来利用现成代码加以调整来满足新的需求,其实采用设计模式的目的之一就是复用,这两个模式正是复用的体现。当你要用这两种模式的时候都是为你现有软件新增新的功能,一般情况下,如果你是让你的软件新增新的功能操作,你一般要用装饰模式,你如果要为软件新增功能支持,你最好选择适配器模式,你如果想为你的类新增操作你用装饰模式,你如果要引入其他来源的现成代码,你用适配器模式。
观察者模式
这个模式我用的多一个原因就是它可以实现事件功能,当然在C#中可以直接使用事件,但是在C++中却是用可以用此模式发挥的淋漓尽致了,网上曾经的一个考题(猫大叫一声,主人醒来,耗子跑开),就是使用这个模式的最好应用。
外观模式
开发就是能复用的地方就复用,这样才能节省资源,提高效率,外观模式也是一个提供复用其他现成代码的解决方案,你需要实现一个功能,可能现成的代码中就有此功能,但是现成代码可能远远多于你所需要的功能,此时你把这些功能封装起来,再重新提供一个你所需要的接口,这就是这个模式的精髓所在。
1.静态成员:
属性,方法和字段是对象实例所特有的,静态成员可看作是类的全局对象。 静态属性和字段可访问独立于任何对象实例的数据,静态方法可执行与对象类型相关而与对象实例无关的命令。使用静态成员时,不需要实例化对象。且不能用实例来调用静态字段,属性,方法。
2.静态类:
只包含静态成员,不能实例化,密封,不需要构造函数的定义