# 請問有人有深入淺出 第五章:保護隱私的估價程式正解嗎?

• ### 問題

• 主要是這樣

一開始程式都跟書本的一樣，不過書本給了一個臭蟲，來說明封裝的意思

一開始的程式如下

類別DinnerParty.cs如下

namespace Kathleen
{

class DinnerParty
{
public int NumberOfPeople;
public decimal CostOfDecorations = 0;
public decimal CostOfBeveragesPerPerson;
public const int CostOfFoodPerPerson = 25;

public void SetHealthyOption(bool HealthyOption)
{
if (HealthyOption)
{
CostOfBeveragesPerPerson = 5.00M;
}
else
{
CostOfBeveragesPerPerson = 20.00M;
}

}

public void CalculateCostOfDecorations(bool Fancy)
{
if (Fancy)
{
CostOfDecorations  = (NumberOfPeople * 15.00M) + 50.00M;
}
else
{
CostOfDecorations = (NumberOfPeople * 7.50M) + 30.00M;
}

}

public decimal  CalculateCost(bool HealthyOption)
{

decimal Totalcost = CostOfDecorations + ((CostOfBeveragesPerPerson +
CostOfFoodPerPerson) * NumberOfPeople) ;

if (HealthyOption)
{
}
else
{
}
}

}
}

From1.cs如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Kathleen
{
public partial class Form1 : Form
{

DinnerParty dinnerParty;
public Form1()
{
InitializeComponent();
dinnerParty = new DinnerParty() { NumberOfPeople = 5 };
dinnerParty.SetHealthyOption(healthyBox.Checked);
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
DisplayDinnerPartyCost();
}

private void fancyBox_CheckedChanged(object sender, EventArgs e)
{
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
DisplayDinnerPartyCost();
}
private void healthyBox_CheckedChanged(object sender, EventArgs e)
{
dinnerParty.SetHealthyOption(healthyBox.Checked);
DisplayDinnerPartyCost();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
dinnerParty.NumberOfPeople = (int)numericUpDown1.Value;
DisplayDinnerPartyCost();
}
private void DisplayDinnerPartyCost()
{
decimal Cost = dinnerParty.CalculateCost(healthyBox.Checked);
costLabel.Text = Cost.ToString("c");
}
}
}

但是在算總數時會有問題

所以後面說了在類別中要用private

所以加了幾行書上說的如下

private int numberOfPeople;

...........

public void SetPartyOptions(int people, bool fancy)
{
numberOfPeople = people;
CalculateCostOfDecorations(fancy);
}
public int GetNumberOfPeople()
{
return numberOfPeople;
}

可是還是不行

是不是還有那裡要加程式的

2012年5月18日 上午 01:42

### 解答

• 那你先好好的看完第五章

看完之後你要的東西就會出現了

以下為簽名檔，如果你愛拉椅子坐那就是你的問題。
先查MSDN文件庫
才到論壇來發問

這是論壇不是技術支援中心
沒有人得無償解答你的問題

在標題或文章註明很急
不會增加網友回覆速度

• 已標示為解答 2012年5月21日 上午 02:12
2012年5月18日 下午 02:55
• 看到你講的Bug

我第一個直覺就是在numericUpDown1_ValueChanged事件再補上這兩個函式

dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);

```        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
dinnerParty.NumberOfPeople = (int)numericUpDown1.Value;
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);
DisplayDinnerPartyCost();
}```

意為：

確保每次客戶人數更動時，「飲料健康取向」和「裝飾取向」都被重新設定(書上也說了，人數變動時，裝飾費用並未被重新計算)

雖然這樣是解決問題了，但應該不是本書主旨

書本為了講解封裝，中間夾雜其他範例說明，所以你才會迫不及待上來問

• 已編輯 2012年5月19日 上午 04:39
• 已標示為解答 2012年5月21日 上午 02:11
2012年5月19日 上午 04:38

### 所有回覆

• ..

但是在算總數時會有問題

所以後面...

可是還是不行

請問你所說有問題，是那裡有問題，錯誤信息是什麼，是那一行出錯誤信息？

大家一齊探討、學習和研究，謝謝！
MCSD, MCAD, MCSE+I, MCDBA, MCDST, MCSA, MCTS, MCITP, MCPD,
MCT, Microsoft Community Star(TW & HK),
Microsoft MVP for VB.NET since 2003
My MSMVP Blog

2012年5月18日 上午 04:01
• 『還是不行』這句話真的很難懂. 發問請用明確的詞語 , 如果對發問的技巧不熟練, 請閱讀 [張貼文章應注意事項及應提供資訊].

這本書我手上沒有, 不過依據你貼上來的章節名稱. 重點是要明白『不該開放的成員就不要開放』.

也就是說一般我們對於存取修飾詞的使用優先順序大概是 private --> protected --> internalprotected internal-->public

以你的例子, 一開始

public int NumberOfPeople;
public decimal CostOfDecorations = 0;
public decimal CostOfBeveragesPerPerson;
public const int CostOfFoodPerPerson = 25;

這四個欄位成員都是 public, 也就是說其它的物件就有能力更改這四個欄位變數. 往下看到 Form1 Class中的

public Form1()
{
InitializeComponent();
dinnerParty = new DinnerParty() { NumberOfPeople = 5 };
dinnerParty.SetHealthyOption(healthyBox.Checked);
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
DisplayDinnerPartyCost();

}

這邊在建立了 DinnerParty 類別執行個體的時候, 給了一個初始值給 NumberOfPeople 欄位

dinnerParty = new DinnerParty() { NumberOfPeople = 5 };

再回到 DinnerParty 類別, 這個NumberOfPeople 基本上在設計者的原來的想法是可變動的, 也就是這個欄位可能是任何一個數字, 而且這個數字是由外部指定. 因此它絕對不是 private, 最起碼也要是 internal, 為了避免把你搞得更糊塗, 就用 public 吧.

回到 Form1 類別的建構式中

dinnerParty.SetHealthyOption(healthyBox.Checked);
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);

再回到 DinnerParty 類別的相關程式碼

public void SetHealthyOption(bool HealthyOption)
{
if (HealthyOption)
{
CostOfBeveragesPerPerson = 5.00M;
}
else
{
CostOfBeveragesPerPerson = 20.00M;
}

}

public void CalculateCostOfDecorations(bool Fancy)
{
if (Fancy)
{
CostOfDecorations  = (NumberOfPeople * 15.00M) + 50.00M;
}
else
{
CostOfDecorations = (NumberOfPeople * 7.50M) + 30.00M;
}

}

在設計者的概念中, 他要限制 CostOfBeveragesPerPerson 等於 5 或 20, 所以寫了SetHealthyOption 方法, 依照傳入的bool值決定為 5 或 20.

所以 CostOfBeveragesPerPerson 的存取控制就會變得嚴格, 因此要使用 private, 因為試想若是public 的狀況, 在 Form1 類別中這樣寫的話

public Form1()
{
InitializeComponent();
dinnerParty = new DinnerParty() { NumberOfPeople = 5 };
dinnerParty.SetHealthyOption(healthyBox.Checked);
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);

dinnerParty.CostOfBeveragesPerPerson = 1000.0M;

DisplayDinnerPartyCost();
}

這樣就完全破壞掉要限制 CostOfBeveragesPerPerson 不是 5 就是 20 的原則了, 這也就是封裝性被破壞掉.

CalculateCostOfDecorations 這個方法也是有同樣的道理, 你可以自己思考看看.

其它參考 MSDN 文件

在現實生活中，你和誰在一起的確很重要，甚至能改變你的成長軌跡，決定你的人生成敗。 和什麼樣的人在一起，就會有什麼樣的人生。 和勤奮的人在一起，你不會懶惰； 和積極的人在一起，你不會消沈； 與智者同行，你會不同凡響； 與高人為伍，你能登上巔峰。

2012年5月18日 上午 04:07
• Bill Chung 大大:
打從心底裡佩服！
如果他說的"有問題" 或 "不行" 不是你所想呢？

大家一齊探討、學習和研究，謝謝！
MCSD, MCAD, MCSE+I, MCDBA, MCDST, MCSA, MCTS, MCITP, MCPD,
MCT, Microsoft Community Star(TW & HK),
Microsoft MVP for VB.NET since 2003
My MSMVP Blog

2012年5月18日 上午 04:23
• Dear Ken:

那就只好繼續討論.不然怎麼辦.

其實我上面忘了說一句話, 這位發問者恐怕看書是劃錯重點的, 這個章節的用意應該在於闡釋物件導向中的封裝, 也就是探討『成員隱藏與保護』，發問者似乎應該先從理解此原理著手, 而不是拘泥在程式碼的執行結果上.

在現實生活中，你和誰在一起的確很重要，甚至能改變你的成長軌跡，決定你的人生成敗。 和什麼樣的人在一起，就會有什麼樣的人生。 和勤奮的人在一起，你不會懶惰； 和積極的人在一起，你不會消沈； 與智者同行，你會不同凡響； 與高人為伍，你能登上巔峰。

2012年5月18日 上午 04:29
• 設計是這樣的，流程是食物25元->選擇5元(總費用5%折扣)or20元飲料->選擇15元(加50元設置費)or7.5元(加30元設置費)裝飾

前面貼的程式是可執行的，沒有執行上的問題，不過在執行的結果有問題，因為在改變人數時CalculateCostOfDecorations這一個沒有再被呼叫，要去點Fancy Decorations才會是正確的結果。

所以後面書中有說要讓某些資料為類別所私有，所以要在DinnerParty中加上

private int numberOfPeople;

...........

public void SetPartyOptions(int people, bool fancy)
{
numberOfPeople = people;
CalculateCostOfDecorations(fancy);
}
public int GetNumberOfPeople()
{
return numberOfPeople;
}

如果單純只加上上面的，如下

class DinnerParty
{

private int numberOfPeople;
public int NumberOfPeople;
public decimal CostOfDecorations = 0;
public decimal CostOfBeveragesPerPerson;
public const int CostOfFoodPerPerson = 25;

public void SetPartyOptions(int people, bool fancy)
{
numberOfPeople = people;
CalculateCostOfDecorations(fancy);
}
public int GetNumberOfPeople()
{
return numberOfPeople;
}

public void SetHealthyOption(bool HealthyOption)

..............

.....

一樣可以執行，也不會有問題

不過cost的結果還是不正確

ps:我說的不行是這個，不好意思沒說明清楚

現在想知道的是書中說的加上這幾行，是還有那應該要加程式的

被版主說中了…現在想知道的是還要加什麼才有正確的結果

很感謝版主的回覆，我會多看幾次你的回覆，還有連結的

很多不懂，麻煩了

謝謝^^

2012年5月18日 上午 05:51
• 一步一步來吧, 先找 Form1 類別中, 你既有的程式有哪些會呼叫到以下三個欄位 (變數) ?

public int NumberOfPeople;
public decimal CostOfDecorations = 0;
public decimal CostOfBeveragesPerPerson;

在現實生活中，你和誰在一起的確很重要，甚至能改變你的成長軌跡，決定你的人生成敗。 和什麼樣的人在一起，就會有什麼樣的人生。 和勤奮的人在一起，你不會懶惰； 和積極的人在一起，你不會消沈； 與智者同行，你會不同凡響； 與高人為伍，你能登上巔峰。

2012年5月18日 上午 09:42
• 呼叫NumberOfPeople

dinnerParty = new DinnerParty() { NumberOfPeople = 5 };

numericUpDown1_ValueChanged

-----------------------------------------------------

呼叫public decimal CostOfDecorations = 0;

dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);

fancyBox_CheckedChanged

-----------------------------------------------------

呼叫public decimal CostOfBeveragesPerPerson;

DisplayDinnerPartyCost()

以上，有錯嗎?

2012年5月18日 上午 09:58
• 我只想問你有把第五章看完嗎????

以下為簽名檔，如果你愛拉椅子坐那就是你的問題。
先查MSDN文件庫
才到論壇來發問

這是論壇不是技術支援中心
沒有人得無償解答你的問題

在標題或文章註明很急
不會增加網友回覆速度

2012年5月18日 上午 10:58
• 還在看下去
2012年5月18日 上午 11:22
• 那你先好好的看完第五章

看完之後你要的東西就會出現了

以下為簽名檔，如果你愛拉椅子坐那就是你的問題。
先查MSDN文件庫
才到論壇來發問

這是論壇不是技術支援中心
沒有人得無償解答你的問題

在標題或文章註明很急
不會增加網友回覆速度

• 已標示為解答 2012年5月21日 上午 02:12
2012年5月18日 下午 02:55
• 看到你講的Bug

我第一個直覺就是在numericUpDown1_ValueChanged事件再補上這兩個函式

dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);

```        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
dinnerParty.NumberOfPeople = (int)numericUpDown1.Value;
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);
DisplayDinnerPartyCost();
}```

意為：

確保每次客戶人數更動時，「飲料健康取向」和「裝飾取向」都被重新設定(書上也說了，人數變動時，裝飾費用並未被重新計算)

雖然這樣是解決問題了，但應該不是本書主旨

書本為了講解封裝，中間夾雜其他範例說明，所以你才會迫不及待上來問

• 已編輯 2012年5月19日 上午 04:39
• 已標示為解答 2012年5月21日 上午 02:11
2012年5月19日 上午 04:38
• 謝謝上面幾位大大的說明。我會先看下去在來解前面的問題

謝謝

2012年5月21日 上午 02:10