构造函数的运用,体现类的自我维护

简介:

构造函数有很多用处,巧妙地运用构造函数能提高类的设计安全、合理和封装。

下面的类设计的不合理,要求用户在调用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 }

把代码改为下面就合理的多
 

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 }


通过构造函数,强制用户在实例化的时候给与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 }


通过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 }

上面的代码看似很合理,用户可以自己定义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 }

我们添加了一个默认的构造函数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 }

看到了吗?在这个代码中,如果用户给与了Number则使用用户给与的值,否则,Order能自动给与值。向用户封装了CreateOrderNumber的存在。这就是类设计的一个很重要的原则:自我维护。
 

本文转自shyleoking 51CTO博客,原文链接:http://blog.51cto.com/shyleoking/806286


相关文章
|
3月前
|
缓存 项目管理
类与类之间的协作模式问题之享元模式在工作中应用的问题如何解决
类与类之间的协作模式问题之享元模式在工作中应用的问题如何解决
|
3月前
|
项目管理
类与类之间的协作模式问题之抽象工厂模式在工作中体现的问题如何解决
类与类之间的协作模式问题之抽象工厂模式在工作中体现的问题如何解决
|
设计模式 Java 数据库连接
JAVA设计模式8:装饰模式,动态地将责任附加到对象上,扩展对象的功能
JAVA设计模式8:装饰模式,动态地将责任附加到对象上,扩展对象的功能
|
Java C++
面对对象三大特性:封装、继承、多态
面对对象三大特性:封装、继承、多态
|
JSON 数据库 数据格式
【工作中问题解决实践 六】基于反射及类装饰模式的数据对比框架(下)
【工作中问题解决实践 六】基于反射及类装饰模式的数据对比框架(下)
113 0
|
设计模式 JSON 数据格式
【工作中问题解决实践 六】基于反射及类装饰模式的数据对比框架(上)
【工作中问题解决实践 六】基于反射及类装饰模式的数据对比框架(上)
115 0
|
安全 Java
创建对象的相关知识补充
创建对象的相关知识补充
62 0
|
Java
Java中多态的概述、成员访问特点、好处弊端及多态的转型
多态的概述、成员访问特点、好处弊端及多态的转型的简单示例
138 0
Java中多态的概述、成员访问特点、好处弊端及多态的转型
|
设计模式 前端开发 C#
C#开发中使用委托的作用和好处
先看概念,什么是委托? 从程序的角度来讲:你就可以把委托看成是用来执行方法(函数)的一个“指针” 通俗的说就是:通过委托,我们可以把方法当成参数传递。 这里我举个例子:“设想,如果我们写了一个厨师做菜的方法,里面有拿菜、切菜、配菜、炒菜四个步骤,但编写此方法代码的人想让配菜这个环节让调用方法的人来实现,换句话说,就是想把方法作为参数来传递,那么怎么来实现呢? 方法1:使用接口,这里不是我们讨论的。
7536 0
|
测试技术 领域建模 数据安全/隐私保护
用“实例化需求”,让需求澄清更高效(上)
用“实例化需求”,让需求澄清更高效(上)
628 0
用“实例化需求”,让需求澄清更高效(上)