当年有幸听了一堂微软MVP专家王豫祥老师的编程课,收益匪浅,现整理如下,供大家学习。
需求:设计一个订单类,该类可以实现自动的订单流水号。
1. 简单实现
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
order1.BillNumber = "20160310-1";
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order();
order2.BillNumber = "20160310-2";
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order();
order3.BillNumber = "20130310-3";
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 3, order3.BillNumber, order3.CreateDate);
Console.ReadLine();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
public string BillNumber
{
set;
get;
}
public readonly DateTime CreateDate = DateTime.Now;
}
}
不足现象:没有实现自动流水订单号
2. 提供自动流水订单号
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
order1.BillNumber = order1.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order();
order2.BillNumber = order1.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order();
order3.BillNumber = order1.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 3, order3.BillNumber, order3.CreateDate);
System.Console.ReadLine();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
public string BillNumber
{
set;
get;
}
public readonly DateTime CreateDate = DateTime.Now;
public string CreateBillNumber()
{
count++;
return DateTime.Now.ToString("yyyyMMdd-") + count.ToString();
}
}
}
产生流水的订单由其实例提供,这种模型不完善,不优雅
3. 静态实现订单流水号
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
order1.BillNumber = order1.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order();
order2.BillNumber = order2.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order();
order3.BillNumber = order3.CreateBillNumber();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 3, order3.BillNumber, order3.CreateDate);
System.Console.ReadLine();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
public Order()
{
count++;
}
public string BillNumber
{
set;
get;
}
public readonly DateTime CreateDate = DateTime.Now;
public string CreateBillNumber()
{
return DateTime.Now.ToString("yyyyMMdd-") + count.ToString();
}
}
}
不足现象:不能挑号
4. 构造函数赋值
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order("dba");
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 3, order3.BillNumber, order3.CreateDate);
System.Console.ReadLine();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
/// <summary>
/// 用户给定订单号
/// </summary>
/// <param name="number"></param>
public Order(string number)
{
BillNumber = number;
}
/// <summary>
/// 自动流水号
/// </summary>
public Order()
{
count++;
BillNumber = CreateBillNumber();
}
public string BillNumber
{
set;
get;
}
public readonly DateTime CreateDate = DateTime.Now;
public string CreateBillNumber()
{
return DateTime.Now.ToString("yyyyMMdd-") + count.ToString();
}
}
}
实例Order时非常自然,如果没有在构造时赋值,则自动流水号产生,否则使用用户给予的号码。CreateBillNumber这个方法对用户透明了,因此我们可以直接封装这个方法。
5. 封装CreateBillNumber
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order("dba");
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 3, order3.BillNumber, order3.CreateDate);
System.Console.ReadLine();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
/// <summary>
/// 用户给定订单号
/// </summary>
/// <param name="number"></param>
public Order(string number)
{
BillNumber = number;
}
/// <summary>
/// 自动流水号
/// </summary>
public Order()
: this(CreateBillNumber())
{
}
public string BillNumber
{
set;
get;
}
public readonly DateTime CreateDate = DateTime.Now;
private static string CreateBillNumber()
{
count++;
return DateTime.Now.ToString("yyyyMMdd-") + count.ToString();
}
}
}
对于用户的要求已经非常的贴切,如果是默认构造则产生自动流水订单号,否则使用用户给予的号码。而且,Order在构造时候,必须要求给予订单号(默认自动或用户指定),而且该订单号一旦产生就不可以变化。
缺陷:当用户要求流水号的格式有变化时,就会打破这个封装。而且由于static方法在继承上下不能被改变,所以不能通过子类来重写。
6. 接口提升封装
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber, order1.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order2 = new Order("dba");
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(2000);
Order order3 = new Order(new InvoiceNumberFormat());
Order order4 = new Order(new InvoiceNumberFormat());
Order order5 = new Order(new InvoiceNumberFormat());
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 5, order5.BillNumber, order5.CreateDate);
System.Console.ReadLine();
}
}
public interface IOrderNumberFormat
{
string CreateBillNumber(int serialNumber);
}
public class InvoiceNumberFormat : IOrderNumberFormat
{
public string CreateBillNumber(int serialNumber)
{
return "***-" + serialNumber.ToString();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
/// <summary>
/// 用户给定订单号
/// </summary>
/// <param name="number"></param>
public Order(string number)
{
BillNumber = number;
}
/// <summary>
/// 自动流水号
/// </summary>
public Order()
: this(CreateBillNumber(CreateSerialNumber()))
{
}
public Order(IOrderNumberFormat numberFormat)
: this(numberFormat.CreateBillNumber(CreateSerialNumber()))
{
}
public readonly string BillNumber;
public readonly DateTime CreateDate = DateTime.Now;
private static int CreateSerialNumber()
{
return ++count;
}
private static string CreateBillNumber(int serialNumber)
{
return DateTime.Now.ToString("yyyyMMdd-") + serialNumber.ToString();
}
}
}
到目前为止,Order关于订单的格式就完善多了,用户可以任意的扩展订单的流水格式,而又不破坏封装。
7. 优化接口实现
如果用户的前缀总是非常简单的字符串常数表达形式,则我们总是为一个简单的常数表达式去实现接口,增大了开销,因此我们优化接口的实现。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Order order1 = new Order("20130313-1");
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 1, order1.BillNumber,order1.CreateDate);
System.Threading.Thread.Sleep(5000);
Order order2 = new Order();
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 2, order2.BillNumber, order2.CreateDate);
System.Threading.Thread.Sleep(5000);
Order order3 = new Order(new InvoiceNumberFormat());
Order order4 = new Order(new InvoiceNumberFormat());
Order order5 = new Order(new InvoiceNumberFormat());
Console.WriteLine("order{0} BillNumber is {1},CreateData at {2}", 5, order5.BillNumber, order5.CreateDate);
System.Console.ReadLine();
}
}
public interface IOrderNumberFormat
{
string CreateBillNumber(int serialNumber);
}
public class InvoiceNumberFormat : IOrderNumberFormat
{
public string CreateBillNumber(int serialNumber)
{
return "***-" + serialNumber.ToString();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
private static int count = 0;
/// <summary>
/// 用户给定订单号
/// </summary>
/// <param name="number"></param>
public Order(string number)
{
BillNumber = number;
}
/// <summary>
/// 自动流水号
/// </summary>
public Order()
: this(CreateBillNumber(CreateSerialNumber()))
{
}
public Order(IOrderNumberFormat numberFormat)
: this(numberFormat.CreateBillNumber(CreateSerialNumber()))
{
}
public readonly string BillNumber;
public readonly DateTime CreateDate = DateTime.Now;
private static int CreateSerialNumber()
{
return ++count;
}
private static string CreateBillNumber(int serialNumber)
{
return DateTime.Now.ToString("yyyyMMdd-") + serialNumber.ToString();
}
}
public class StringOrderNumberFormat : IOrderNumberFormat
{
public readonly string FormatString;
public StringOrderNumberFormat(string formatString)
{
FormatString = formatString;
}
public string CreateBillNumber(int serialNumber)
{
return FormatString + serialNumber.ToString();
}
}
}