构造函数有很多用处,巧妙地运用构造函数能提高类的设计安全、合理和封装。
下面的类设计的不合理,要求用户在调用18行Pring方法前,先为17行赋值。
通过构造函数,强制用户在实例化的时候给与FileName的值,调用更安全更简约。
第23行对数据成员FileName修饰为readonly表示该数据成员为只读,只读的意思是,该成员只有一次赋值的机会(声明时立即赋值或在构造函数时赋值)。readonly和const的区别是
readonly有两种赋值的机会:声明时立即赋值或在构造函数时赋值
const只有在声明时赋值
另外一个很值得注意的是,const其实就是static数据修饰,不过不能直接用static来修饰。const包括了static的含义,所以const需要通过类来访问。
我们再来看一个构造函数的运用
请仔细考虑一下代码
下面的类设计的不合理,要求用户在调用18行Pring方法前,先为17行赋值。
1
public class Space
2
{
3![]()
4
public static void Main(string[] args)
5
{
6![]()
7
FilePrint pring = new FilePrint();
8
//如果用户忘记调用FileName,系统将不可靠
9
//pring.FileName = @"c:\text.txt";
10
pring.Print();
11
}
12
}
13![]()
14
public class FilePrint
15
{
16![]()
17
public string FileName = null;
18
public void Print()
19
{
20
System.Console.WriteLine("Do prining {0}", FileName);
21
}
22
}
把代码改为下面就合理的多
public class Space2
{3

4
public static void Main(string[] args)5
{6

7
FilePrint pring = new FilePrint();8
//如果用户忘记调用FileName,系统将不可靠9
//pring.FileName = @"c:\text.txt";10
pring.Print();11
}12
}13

14
public class FilePrint15
{16

17
public string FileName = null;18
public void Print()19
{20
System.Console.WriteLine("Do prining {0}", FileName);21
}22
} 1
public class Space
2
{
3![]()
4
public static void Main(string[] args)
5
{
6![]()
7
FilePrint pring = new FilePrint(@"c:\text.txt");
8
pring.Print();
9![]()
10
//代码可以更简约
11
new FilePrint(@"c:\text.txt").Print();
12
}
13
}
14![]()
15
public class FilePrint
16
{
17![]()
18
public FilePrint(string path)
19
{
20
FileName = path;
21
}
22![]()
23
public readonly string FileName = null;
24
public void Print()
25
{
26
System.Console.WriteLine("Do prining {0}", FileName);
27
}
28
}
public class Space2
{3

4
public static void Main(string[] args)5
{6

7
FilePrint pring = new FilePrint(@"c:\text.txt");8
pring.Print();9

10
//代码可以更简约11
new FilePrint(@"c:\text.txt").Print();12
}13
}14

15
public class FilePrint16
{17

18
public FilePrint(string path)19
{20
FileName = path;21
}22

23
public readonly string FileName = null;24
public void Print()25
{26
System.Console.WriteLine("Do prining {0}", FileName);27
}28
}通过构造函数,强制用户在实例化的时候给与FileName的值,调用更安全更简约。
第23行对数据成员FileName修饰为readonly表示该数据成员为只读,只读的意思是,该成员只有一次赋值的机会(声明时立即赋值或在构造函数时赋值)。readonly和const的区别是
readonly有两种赋值的机会:声明时立即赋值或在构造函数时赋值
const只有在声明时赋值
另外一个很值得注意的是,const其实就是static数据修饰,不过不能直接用static来修饰。const包括了static的含义,所以const需要通过类来访问。
我们再来看一个构造函数的运用
请仔细考虑一下代码
1
public class Space
2
{
3![]()
4
public static void Main(string[] args)
5
{
6![]()
7
System.Console.WriteLine(new SalesContract(100).SalePrice);
8
System.Console.WriteLine(new SalesContract(100,120).SalePrice);
9
System.Console.WriteLine(new SalesContract(100,120,180).SalePrice);
10![]()
11![]()
12
}
13
}
14![]()
15
public class SalesContract : Contract//销售合同
16
{
17
public SalesContract(double costPrice)
18
: this(costPrice, costPrice)
19
{ }
20![]()
21
public SalesContract(double costPrice, double minimumPrice)
22
: this(costPrice, minimumPrice, minimumPrice)
23
{ }
24![]()
25
public SalesContract(double costPrice, double minimumPrice, double salePrice)
26
{
27
CostPrice = costPrice;
28
MinimumPrice = minimumPrice;
29
SalePrice = salePrice;
30
}
31![]()
32
private double MinimumPrice;//最低价
33
public double SalePrice;//销售价格
34![]()
35
public bool CheckPrice()//价格检查
36
{
37
return SalePrice < Math.Min(MinimumPrice, CostPrice);
38
}
39
internal double PreferentialPrice;//优惠价
40
}
41![]()
42
public class Contract//合同
43
{
44![]()
45
public string Buyer;//买方
46
public string Seller;//卖方
47
protected double CostPrice;//成本价
48
}
public class Space2
{3

4
public static void Main(string[] args)5
{6

7
System.Console.WriteLine(new SalesContract(100).SalePrice);8
System.Console.WriteLine(new SalesContract(100,120).SalePrice);9
System.Console.WriteLine(new SalesContract(100,120,180).SalePrice);10

11

12
}13
}14

15
public class SalesContract : Contract//销售合同 16
{17
public SalesContract(double costPrice)18
: this(costPrice, costPrice)19
{ }20

21
public SalesContract(double costPrice, double minimumPrice)22
: this(costPrice, minimumPrice, minimumPrice)23
{ }24

25
public SalesContract(double costPrice, double minimumPrice, double salePrice)26
{27
CostPrice = costPrice;28
MinimumPrice = minimumPrice;29
SalePrice = salePrice;30
}31

32
private double MinimumPrice;//最低价33
public double SalePrice;//销售价格 34

35
public bool CheckPrice()//价格检查36
{37
return SalePrice < Math.Min(MinimumPrice, CostPrice);38
}39
internal double PreferentialPrice;//优惠价40
}41

42
public class Contract//合同43
{44

45
public string Buyer;//买方46
public string Seller;//卖方47
protected double CostPrice;//成本价48
}
通过3个构造函数,用户可以方便的对ConstPrice、SalePrice、MinimunPrice进行赋值。
我们再来看一个关于构造函数的用例。
1
public class Space
2
{
3![]()
4
public static void Main(string[] args)
5
{
6
System.Console.WriteLine(new Order("123-12").OrderNumber);
7
System.Console.WriteLine(new Order(Order.CreateOrderNumber()).OrderNumber);
8
System.Console.WriteLine(new Order(Order.CreateOrderNumber()).OrderNumber);
9
}
10
}
11![]()
12
public class Order
13
{
14![]()
15
public Order(string orderNumber)
16
{
17
this.OrderNumber = orderNumber;
18
}
19![]()
20
private static int Count;
21![]()
22
public readonly string OrderNumber;
23![]()
24
public static string CreateOrderNumber()
25
{
26
System.DateTime d = System.DateTime.Now;
27
return System.DateTime.Now.ToString("yMd-") + (++Count).ToString();
28
}
29![]()
30
}
public class Space2
{3

4
public static void Main(string[] args)5
{6
System.Console.WriteLine(new Order("123-12").OrderNumber);7
System.Console.WriteLine(new Order(Order.CreateOrderNumber()).OrderNumber);8
System.Console.WriteLine(new Order(Order.CreateOrderNumber()).OrderNumber);9
}10
}11

12
public class Order13
{14

15
public Order(string orderNumber)16
{17
this.OrderNumber = orderNumber;18
}19

20
private static int Count;21

22
public readonly string OrderNumber;23

24
public static string CreateOrderNumber()25
{26
System.DateTime d = System.DateTime.Now;27
return System.DateTime.Now.ToString("yMd-") + (++Count).ToString();28
}29

30
}上面的代码看似很合理,用户可以自己定义OrderNumber也可以通过CreateOrderNumber方法,Order在构造时总是可以得到Number。
但这样的设计,暴露了对CreateOrderNumber的调用。
我们看看经过修改后的设计
1
public class Order
2
{
3![]()
4
public Order(string orderNumber)
5
{
6
this.OrderNumber = orderNumber;
7
}
8![]()
9
public Order():this(CreateOrderNumber())
10
{
11
12
}
13![]()
14
private static int Count;
15![]()
16
public readonly string OrderNumber;
17![]()
18
private static string CreateOrderNumber()
19
{
20
System.DateTime d = System.DateTime.Now;
21
return System.DateTime.Now.ToString("yMd-") + (++Count).ToString();
22
}
23![]()
24
}
public class Order2
{3

4
public Order(string orderNumber)5
{6
this.OrderNumber = orderNumber;7
}8

9
public Order():this(CreateOrderNumber())10
{ 11
12
}13

14
private static int Count;15

16
public readonly string OrderNumber;17

18
private static string CreateOrderNumber()19
{20
System.DateTime d = System.DateTime.Now;21
return System.DateTime.Now.ToString("yMd-") + (++Count).ToString();22
}23

24
}我们添加了一个默认的构造函数Order()在第9行,又把18行的CreateOrderNumber改为private,那么这会有什么效果呢?
1
public class Space
2
{
3![]()
4
public static void Main(string[] args)
5
{
6
System.Console.WriteLine(new Order("123-12").OrderNumber);
7
System.Console.WriteLine(new Order().OrderNumber);
8
System.Console.WriteLine(new Order().OrderNumber);
9
}
10
}
public class Space2
{3

4
public static void Main(string[] args)5
{6
System.Console.WriteLine(new Order("123-12").OrderNumber);7
System.Console.WriteLine(new Order().OrderNumber);8
System.Console.WriteLine(new Order().OrderNumber);9
}10
}看到了吗?在这个代码中,如果用户给与了Number则使用用户给与的值,否则,Order能自动给与值。向用户封装了CreateOrderNumber的存在。这就是类设计的一个很重要的原则:自我维护。

浙公网安备 33010602011771号