1.需求分析
2.设计类
3.类的实现过程
3.1 设计类
1.答案类
/// <summary>
/// 答案类
/// </summary>
[Serializable]
public class Answer
{
public string RightAnswer { get; set; }=string.Empty;
public string SelectedAnswer { get; set; }=string.Empty;
public string AnswerAnalysis { get; set; }=string.Empty;
}
2.试题类
/// <summary>
/// 试题类
/// </summary>
[Serializable]
class Question
{
public Question()
{
QAnswer = new Answer();//初始化对象属性,避免错误:未将对象引用到实例
}
public int QuestionId { get; set; }
public string QuestionTitle { get; set; }
public string OptionA { get; set; }
public string OptionB { get; set; }
public string OptionC { get; set; }
public string OptionD { get; set; }
public Answer QAnswer{ get; set; }//答案(对象属性)
}
3.试卷类
/// <summary>
/// 试卷类
/// </summary>
class Paper
{
public Paper()
{
this.questions = new List<Question>();
}
/// <summary>
/// 试题集合对象
/// </summary>
private List<Question> questions;
public List<Question> Questions
{
get{return this.questions;}
}
/// <summary>
/// 当提供给用户的题目文档为txt格式时,提取文档中的字符串转化为对象集合
/// </summary>
public void ExtractQuestions()
{
FileStream fs = new FileStream("questions.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs,Encoding.Default);
string content = sr.ReadToEnd();
string[] questionArray = content.Split(Convert.ToChar("&"));
string[] question = null;
foreach (string item in questionArray)
{
question = item.Trim().Split(Convert.ToChar("\r"));
this.questions.Add(new Question
{
QuestionTitle = question[0].Trim(),
OptionA = question[1].Trim(),
OptionB = question[2].Trim(),
OptionC = question[3].Trim(),
OptionD = question[4].Trim(),
QAnswer = new Answer { RightAnswer = question[5].Trim() }
});
sr.Close();
fs.Close();
SavePaper();
}
}
/// <summary>
/// 将题目集合序列化
/// </summary>
private void SavePaper()
{
FileStream fs = new FileStream("question.obj", FileMode.Create);
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, this.questions);
fs.Close();
}
/// <summary>
/// 当提供给用户的文档是自定义类型的文件,抽取文件中的全部试题及将磁盘中的文件反序列化为对象集合
/// </summary>
/// <returns></returns>
public void ExtractQuestions()
{
FileStream fs = new FileStream("question.obj", FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
this.questions = (List<Question>)bf.Deserialize(fs);
fs.Close();
}
/// <summary>
/// 提交试卷
/// </summary>
/// <returns></returns>
public int SubmitPaper()
{
int score = 0;
foreach (Question item in this.questions)
{
if (item.QAnswer.SelectedAnswer == "") continue;
if (item.QAnswer.RightAnswer.Equals(item.QAnswer.SelectedAnswer))
score += 5;
}
return score;
}
3.2 功能实现
public partial class FrmMain : Form
{
private Paper paper=new Paper();
private int questionIndex = 0;//当前试题的序号
public FrmMain()
{
InitializeComponent();
}
//抽取试题
private void btnExtract_Click(object sender, EventArgs e)
{
paper.ExtractQuestions();
//隐藏抽取试题面板和按钮
this.panelPaper.Visible = false;
this.btnExtract.Visible = false;
//显示第一题
ShowQuestion();
}
private void ShowQuestion()
{
this.lblTitle.Text = paper.Questions[this.questionIndex].QuestionTitle;
this.lblA.Text = paper.Questions[this.questionIndex].OptionA;
this.lblB.Text = paper.Questions[this.questionIndex].OptionB;
this.lblC.Text = paper.Questions[this.questionIndex].OptionC;
this.lblD.Text = paper.Questions[this.questionIndex].OptionD;
}
private void SaveAnswer()
{
string answer = string.Empty;
if (this.ckbA.Checked)
answer += "A";
if (this.ckbB.Checked)
answer += "B";
if (this.ckbC.Checked)
answer += "C";
if (this.ckbD.Checked)
answer += "D";
//找到当前试题对象,保存当前用户所选答案
paper.Questions[questionIndex].QAnswer.SelectedAnswer = answer;
}
//上一题
private void btnPre_Click(object sender, EventArgs e)
{
if (questionIndex == 0) return;
else
{
SaveAnswer();
this.questionIndex--;
ShowQuestion();
ResetAnswer();
}
}
//下一题
private void btnNext_Click(object sender, EventArgs e)
{
if (questionIndex == paper.Questions.Count - 1) return;
else
{
SaveAnswer();
this.questionIndex++;
ShowQuestion();
ResetAnswer();
}
}
/// <summary>
/// 重置答案(在上一题、下一题选择中,如果试题已经选过答案,则显示以前选择的答案)
/// </summary>
private void ResetAnswer()
{
this.ckbA.Checked = paper.Questions[this.questionIndex].QAnswer.SelectedAnswer.Contains("A");
this.ckbB.Checked = paper.Questions[this.questionIndex].QAnswer.SelectedAnswer.Contains("B");
this.ckbC.Checked = paper.Questions[this.questionIndex].QAnswer.SelectedAnswer.Contains("C");
this.ckbD.Checked = paper.Questions[this.questionIndex].QAnswer.SelectedAnswer.Contains("D");
}
//提交试卷
private void btnSubmit_Click(object sender, EventArgs e)
{
SaveAnswer();//保存最后一次用户所选的答案
//计算分数
int score = this.paper.SubmitPaper();
this.panelPaper.Visible = true;
this.lblInfo.Text= "您当前成绩为: {score}分!";
}
//关闭窗体
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
}
4.疑问和解答
1.实体类为什么要序列化
引用:https://blog.csdn.net/sanluo11/article/details/70598448
简单的说就是每当客户端访问某个能开启会话功能的资源,web服务器就会创建一个HTTPSession对象,每个HTTPSession对象都会占用一定的内存,如果在同一个时间段内访问的用户太多,就会消耗大量的服务器内存,为了解决这个问题我们使用一种技术:session的持久化
什么是session持久化?
web服务器会把暂时不活动的并且没有失效的HTTPSession对象转移到文件系统或数据库中储存,服务器要用时在把他们转载到内存。
现在我们言归正传,为什么要实现序列化?
把HTTPSession保存到文件系统或数据库中需要采用序列化的方式,把HTTPSession从文件系统或数据库中装载到内存需要采用反序列化来恢复对象的每个属性,所以我们要实现java.io.Serializable
我的理解:就像我们搬桌子,桌子太大了不能通过比较小的门,所以我们要把它拆了再运进去,这个拆桌子的过程就是序列化。
而反序列化就是等我们需要用桌子的时候再把它组装起来,这个过程就是反序列化
假如一个亿的用户同时访问某网站,web服务器会创建一个亿HTTPSession对象,每个Session都有自己业务相关的pojo实体类对象,这些数据在使用的时候,存放于内存中。在不用的时候存放于磁盘中。序列化目的就是为了解决数据从磁盘到内存的相互转换,称之为序列化和反序列化。
所以
最重要的两个原因是:
1、将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;
2、按值将对象从一个应用程序域发送至另一个应用程序域。
实现serializable接口的作用是就是可以把对象存到字节流,然后可以恢复。所以你想如果你的对象没实现序列化怎么才能进行网络传输呢,要网络传输就得转为字节流,所以在分布式应用中,你就得实现序列化,如果你不需要分布式应用,那就没那个必要实现序列化。
ps:分布式应用(distributed application)指的是应用程序分布在不同计算机上,通过网络来共同完成一项任务的工作方式。