定義課程Course
public?class?Course{
///?<summary>
///?課程名稱
///?</summary>
public?string?Name{get;set;}
///?<summary>
///?課程學分
///?</summary>
public?int?Score{get;set;}
}
定義學生類:
public?class?Student{
#region?字段
///?<summary>
///?存儲學生課程得分
///?</summary>
private?Dictionary<Course,?int>?_Scores?=?new?Dictionary<Course,?int>();
#endregion?字段
#region?屬性
///?<summary>
///?學號
///?</summary>
public?string?Id{get;set;}
///?<summary>
///?姓名
///?</summary>
public?string?Name{get;set;}
#endregion?屬性
#region?成員方法
///?<summary>
///?添加學生課程成績
///?</summary>
///?<param?name="course">課程信息</param>
///?<param?name="score">學生成績</param>
public?void?AddCourseScore(Course?course,?int?score)
{
if(course?==?null)?return?;
if(_Scores.ContainsKey(course))
_Scores[course]?=?score;
else
_Scores.Add(course,?score);
}
///?<summary>
///?獲得學生平均分
///?</summary>
///?<param?name="gpa">計算方式</param>
///?<returns>平均分</returns>
public?double?GetGPAScore(GPA?gpa)
{
gpa.AddScores(_Scores);
return?gpa.GetScore();
}
public?void?Display()
{
Console.WriteLine($"學號:{Id},姓名:{Name}");
Console.WriteLine("?課程名學分成績");
foreach(var?item?in?_Scores)
Console.WriteLine($"?{item.Key.Name}{item.Key.Score}?{item.Value}");
}
#endregion?成員方法
}
獲得平均分的地方直接使用了策略算法,策略算法的好處就是以後方便妳使用其他計算平均分的方式,比如計算每科的平均分等,我會在代碼中給出,以方便妳能看到策略算法的好處,所以此會我會定義策略算法的家族:
public?abstract?class?GPA{
#region?屬性
///?<summary>
///?存儲課程列表
///?</summary>
protected?Dictionary<Course,?int>?_Scores?=?new?Dictionary<Course,?int>();
#endregion?屬性
#region?成員方法
///?<summary>
///?獲得平均分
///?</summary>
///?<returns>平均分數</returns>
///?<remark>
///?定義算法家族,由子類實現
///?</remark>
public?abstract?double?GetScore();
///?<summary>
///?添加算法必要的參數
///?</summary>
///?<param?name="scores"></param>
public?void?AddScores(Dictionary<Course,int>?scores){
_Scores?=?scores;
}
#endregion?成員方法
}
當然,以後每種算法均可以繼承這個抽象類即可:如以下三個算法的定義:
///?<summary>///?計算常見GPA平均分
///?</summary>
public?class?GenericGPA
:?GPA
{
///?<summary>
///?計算壹般GPA平均分
///?</summary>
///?<returns>平均分</returns>
public?override?double?GetScore()
{
if(_Scores.Count?==?0)?return?0;
double?sum?=?0,?total?=0;
foreach(KeyValuePair<Course,int>?item?in?_Scores){
sum?+=?item.Key.Score;
total?+=?item.Key.Score*GetPoint(item.Value);
}
if(sum?==?0)?return?0;
return?total/sum;
}
///?<summary>
///?計算分值
///?</summary>
///?<param?name="score">分數</param>
///?<returns>級分</returns>
private?double?GetPoint(int?score)
{
int?rslt?=?score/10;
rslt?-=?5;
rslt?=?Math.Max(0,Math.Min(4,rslt));
return?rslt;
}
}
///?<summary>
///?計算標準GPA
///?</summary>
public?class?StandardGGPA
:?GPA
{
///?<summary>
///?計算平均分
///?</summary>
///?<returns></returns>
public?override?double?GetScore()
{
if(_Scores.Count?==?0)?return?0;double?sum?=?0,?total?=0;
foreach(KeyValuePair<Course,int>?item?in?_Scores){
sum?+=?item.Key.Score;
total?+=?item.Key.Score*item.Value;
}
if(sum?==?0)?return?0;
return?total*4/(sum*100.0);
}
}
/*?策略模式的好處就是,如果哪壹天妳想添加壹種新的算法
這是十分容易,妳可以在任何地方繼承GPA,並實現其方法
即可,比如我們不按GPA計算的平均分?*/
public?class?AVG
:?GPA
{
public?override?double?GetScore()
{
if(_Scores.Count?==?0)?return?0;
int?sum?=_Scores.Sum(_Item?=>?_Item.Value);
return?sum*1.0/_Scores.Count;
}
}
調用方式(場景代碼):
class?Program{
static?void?Main(string[]?args)
{
///?<summary>
///?初始化學生
///?</summary>
Student?student?=?new?Student{Id="1",?Name="王華"};
///?初始化課程並添加課程分數
Course?course?=?new?Course{Name="課程2",Score=4};
student.AddCourseScore(course,92);?//?學生在該課程上得到了92分
///?逐次添加各科成績
course?=?new?Course{Name="課程2",Score=3};
student.AddCourseScore(course,80);
//?其實我也很懶的,以下變化壹下寫法
student.AddCourseScore(new?Course{Name="課程3",Score=2},98);
student.AddCourseScore(new?Course{Name="課程4",Score=6},70);
student.AddCourseScore(new?Course{Name="課程5",Score=3},89);
//?顯示學生成績
student.Display();
//?計算GPA平均分算法
GPA?gpa?=?new?GenericGPA();
double?genericScore?=?student.GetGPAScore(gpa);
gpa?=?new?StandardGGPA();
double?standardScore?=?student.GetGPAScore(gpa);
gpa?=?new?AVG();
double?avgScore?=?student.GetGPAScore(gpa);
//?以上語句妳應該看出來這種策略算法的好處了吧?
//?當然有時我們會使用策略+反射的方式進行直接處理
//?這樣只需要把策略配置到配置文件中即可。
Console.WriteLine($"常規算法GPA={genericScore.ToString(".00")},標準算法GPA={standardScore.ToString(".00")};");
Console.Read();
}
}
嗯,基本上編程就是這樣的,如果妳慢慢接觸模式之後,妳的代碼將來會修改盡可能的少。比如AVG算法類就是直接寫壹個新類,然後在場景代碼中直接調用即可,目的就是實現OCP(開閉原則),這種寫法會讓妳感到代碼是不做更改的。
比如我們想調用AVG的算法時,double avg = student.GetGPAScore(new AVG());這樣就好了。場景代碼中只是組裝壹下而已。