论道——工厂模式与装饰模式的融合

        在做项目之前总绝得需求为王很对,但是到自己的代码中,总是感觉不得要领,一直到我们做考试系统,大家讨论需求的时候,需求的各种乱,各种不知道怎么平衡,各种讨论,再到一个个的确定,一个个得多方平衡,才明白,需求就是一切!

        今天给大家介绍一个特殊的需求,在做考试系统的过程中,我们的想要将题型的变化封装到dll里,设计模式里的装饰模式可以做到增加一个新的题型而不动代码,但是他有个弊端就是客户端要实例具体的题型类,我想将创建也 封装起来,就用简单工厂模式对装饰者做了个优化,现在给大家分享:


1,装饰模式第一版:

        论道——工厂模式与装饰模式的融合_第1张图片


代码:


抽象页面

/// 
    /// 装饰者——抽象的页面——组卷的抽象类
    /// 
    public class AbstractPage
    {
       // public double Fraction;
        //展示页面
        public virtual void ShowPage() 
        { } 
    }


问题页面


/// 
    /// 装饰者模式——题的抽象展示页面
    /// 
    public class QuestionsPage:AbstractPage
    {
        //每个题里都有一个页面——可以看做未具体题型在这里的暂存位置,将各个题型的作为另一个题型的属性
        protected AbstractPage LittleQuestionsPage;

        protected static double AllFraction;

        public double GetAllFraction()
        {
            return AllFraction;
        }

        //加入新的题型,做到题型的累加,将各个题型串联起来
        public void AddQuestionsPage(AbstractPage QuestionsPage)
        {
            this.LittleQuestionsPage = QuestionsPage;
        }

        //抽象的显示,显示具体的题型内的题型页面
        public override void ShowPage()
        {
            if (LittleQuestionsPage!=null)
            {
                LittleQuestionsPage.ShowPage();
            }
        }

    }


其中一个具体的页面(选择题



    /// 
    /// 显示选择题——装饰者
    /// 
    public class ChoiceQuestionPage : QuestionsPage
    {

        /// 
        /// 构造类
        /// 
        public ChoiceQuestionPage() 
        {
            

        }
        //抽象的显示,显示具体的题型内的题型页面
        /// 
        /// 显示选择题
        /// 
        public override void ShowPage()
        {
            //较为关键代码——先显示自己包含的装饰者的装饰
            base.ShowPage();


            ///页面显示选择题——略

    }

 总结:

        整个的装饰模式相当于将每个纸片打孔,让他可以和具体的纸片用钩子连接起来,这样牵动最后一个纸片,就会带出所有的纸片,直到纸片上没有钩子!这个在生活中经常用到,比如我们的笔记本:

论道——工厂模式与装饰模式的融合_第2张图片

2,装饰模式第二版:


论道——工厂模式与装饰模式的融合_第3张图片


        这样就用简单工厂封装了装饰者模式客户端分拣的过程,将变化进一步封装,优化了结构,使得变化更加灵活!


代码:

工厂


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ExamSystemV3.Web;
using ExamSystemV3.Model;
using BLL;
using ExamSystemV3.Common;
using System.Globalization;
using System.Data;
using System.Collections;
using System.Web.SessionState;

namespace ExamSystemV3.Web.web_class
{
    public class CreatQuestion
    {
        /// 
        /// 显示dataset里试题的页面
        /// 
        /// 存放试题的dataset 要求:ds.DataSetName+"_"+ dt.TableName + "_Record" 能拼出答题记录表例如:ds.DataSetName="T_tongjixue" dt.TableName="xvanzeti" 则拼接出的答题记录表为"T_tongjixue_xvanzeti_Record" 
        /// 页面中能够盛放试题的div的id
        /// 是否是二次登陆
        /// 考试id
        /// 学号
        /// 返回携带所有问题的QuestionsPage
        public QuestionsPage StuCreateQuestion(DataSet ds)
        {
            int i,j;
            DataTable dt;
            ArrayList arrAllQuestion=new ArrayList();
            ArrayList arrQuestion=new ArrayList();

            //创建所有的题型page类放到arrAllQuestion
            for (i = 0; i <= ds.Tables.Count - 1; i++)
            {

                dt=ds.Tables[i];
                arrQuestion = DataTableToArrylist(dt);
                strRecordTableName =ds.DataSetName+"_"+ dt.TableName + "_Record";
                qsPageLittle = CreatePage(dt, isExaminghtml, _FlagChooseQuestion, BigQuestionNum, arrQuestion, strRecordTableName, _ExamId, _StudentId);
                BigQuestionNum = BigQuestionNum + 1;
                arrAllQuestion.Add( qsPageLittle );
                
                
            }
            //将所有具体的页面封装在一个页面中
            for (j = arrAllQuestion.Count-1; j >= 1; j--)
            {
                qsPageLittle = (QuestionsPage)arrAllQuestion[j - 1];
                ((QuestionsPage)arrAllQuestion[j]).AddQuestionsPage(qsPageLittle);
            }
	    //返回封装好的最后一个页面
            qsPageall = (QuestionsPage)arrAllQuestion[arrAllQuestion.Count - 1];
            return qsPageall;

        
        }
        
        //创建不同的页面
        private QuestionsPage CreatePage(DataTable dt, System.Web.UI.HtmlControls.HtmlGenericControl isExaminghtml, string _FlagChooseQuestion, int _BigQuestionNum, ArrayList _arrAllQuestion, string _strSingleSelectionRecordTableName, string _ExamId, string _StudentId)
        {
            QuestionsPage ChildQuestionPage;
            switch (dt.TableName)
            {

                //ChoiceQuestionPage
                //选择题
                case "xuanzeti":
                    ChildQuestionPage = new ChoiceQuestionPage(isExaminghtml, _FlagChooseQuestion, _BigQuestionNum, _arrAllQuestion, _strSingleSelectionRecordTableName, _ExamId, _StudentId);
                    break;

                //MultiSelectQestionPage
                //多选题
                case "duoxuanti":
                    ChildQuestionPage = new MultiSelectQestionPage(isExaminghtml, _FlagChooseQuestion, _BigQuestionNum, _arrAllQuestion, _strSingleSelectionRecordTableName, _ExamId, _StudentId);
                    break;

                
                // AnalysisQuestionPage
                //案例分析题
                case "anlifenxiti":
                    ChildQuestionPage = new AnalysisQuestionPage(isExaminghtml, _FlagChooseQuestion, _BigQuestionNum, _arrAllQuestion, _strSingleSelectionRecordTableName, _ExamId, _StudentId);
                    break;

               //剩下的略

                default:
                    ChildQuestionPage=null;
                    break;
            }

            return ChildQuestionPage;

        }

}

         大家研究不难发现,其实就是case语句的功劳!


3,装饰模式,简单工厂模式总结:


        我们写代码的时候,要充分考虑封装变化,将变化封装到模块中,增加模块内的内聚性,做到变化的改动尽量不重新生成,即使生成也是很小的改动,增加我们系统的灵活性和可靠性!要多思考,多总结!


注:为了照顾篇幅,本人已精简代码,只保留骨干部分,如有需要查看全部代码,请留言,共同交流!

你可能感兴趣的:(web,三层)