从一个网页生成系统看怎么在程序中实现面向对象三大基本特性

       程序员都知道面向对象编程的三大特性是:封装、继承、多态 ,至于他们的具体含义不是本文要讲的内容,本文要讲的是如何在程序开发过程中利用这三大特性开发出一个具有好的扩展性、复用性、封装性、健壮性的程序,下面我将把我们曾经开发过的一个网页生成系统为例来说明怎么在程序中实现三大特性,同时也会附带说明写程序时如何遵循面向对象的五大基本原则 。
      为了加快网页加载速度,减少与数据库的连接和读取次数,让搜索引擎友好等等,数字化企业网(www.e-works.net.cn)采用的是静态页面,绝大部分网页都是在信息内容发布到数据库的后马上生成静态网页,用户访问网站打开网页时无需从数据库中读取内容,为此我们专门开发网页生成系统。网页生成系统是静态网页网站的最主要也很重要的一个系统,该系统功能虽然简单,但使用率非常高,开发起来很繁琐,重复性劳动多。
         下面先介绍一下我们的网页生成系统的网页生成原理:网站有很类型的网页(比如有首页、各栏目首页、各栏目列表页、各栏目详细内容页等等),每一类型的页面都有与其他类型页面不同,同一类页面的呈现方式是相同的,网页设计人员给每一类页面设计好页面模板,开发人员把模板页面上需要从数据库中读取数据填充的部分先放置一个替换标记,当生成网页的时候,程序先读取网页模板的html代码,然后从数据库中获取此页面需要的数据,用数据拼凑成html代码替换掉网页模板中相应的替换标记,最后利用替换好的页面html代码生成网页文件保存起来就万事大吉了。简单吧,但简单的程序也可以写的很有范。下面我们就结合代码来具体讲解一下我们是怎么实现三大特性的。
      我们发现网页虽然有很多类别,但是他们的生成过程基本都是相同的,都有相同的三步:
      第一步:读取网页模板。第二步:用数据库内容替换模板标记。第三步:保存生成的网页。
      其中第一步读取网页模板时我们把公共部分(头部和尾部)单独做成了一个模板,读取时加了缓存。第二步替换内容时包括替换三个方面的内容:一是替换Seo的内容,二是替换文章内容信息,三是替换广告信息。
    既然大家都有相同的生成过程,那么我们就把这个过程抽象出来,写成一个抽象类,在类中用虚方法把他们的主要步骤表示出来 。具体代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EworksCms.Domain;
using EworksCms.Domain.CreatePage;
using EworksCms.BLInterface;
using EworksCms.BL.AdManage;
using Framework.CreatePageHelper;
using CommTool;

namespace Framework._CreatePage
{
    public abstract class AbstractEworksCreatePage
    {
        private EworksCreateTopicConfig _config;//网站栏目配置信息,包括栏目id,模板路径,广告Id、seo信息等
        public EworksCreateTopicConfig Config
        {
            get { return _config; }
            set { _config = value; }
        }

        /// <summary>
        /// 获取模版页面内容
        /// </summary>
        /// <returns></returns>
        public virtual string GetPageModelContent()
        {
            if (Config != null)
            {
                string modelvirtualfile = Config.ModelPath;//模板虚拟路径
                string physicfile = SitePathHelper.GetModelFilePhysicalPath() + modelvirtualfile.Replace("/", "\\");//模板物理路径
                FileSystem fs = new FileSystem();
                return fs.ReadTxtFile(physicfile, Encoding.UTF8);
            }
            else
                return "";
        }
       

//获取网页头部模板内容
        public virtual string GetPageHeadArea()
        {
            string cachekey = "commpagehead";
            string headinfo = "";
            if (CommTool.Caches.CommonCache.Cache[cachekey] != null)
            {
                headinfo = (string)CommTool.Caches.CommonCache.Cache[cachekey];
            }
            else
            {
                //从模版读取文件数据
                FileSystem fs=new FileSystem();
                headinfo = fs.ReadTxtFile(SitePathHelper.GetModelFilePhysicalPath() + "\\models\\2014Models\\pageheadmodel.html", Encoding.UTF8);
                CommTool.Caches.CommonCache.Cache.Insert(cachekey, headinfo, null, DateTime.Now.AddMinutes(3), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
            }
            return headinfo;
        }
       //获取网页尾部模板内容
        public virtual string GetPageBottomArea()
        {
            return "<script type=\"text/javascript\" src=\"http://www.e-works.net.cn/js/foot2014.js\"></script>";
        }

       //网页用于Seo的title
        public virtual string GetSeoTitle()
        {
            if (Config != null)
                return Config.Title;
            else
                return "";
        }

    //网页用于seo的关键字
        public virtual string GetSeoKeywords()
        {
            if (Config != null)
                return Config.KeyWord;
            else
                return "";
        }

     //网页用于seo的描述
        public virtual string GetSeoDescrption()
        {
            if (Config != null)
                return Config.Descrption;
            else
                return "";
        }

   //替换广告内容
        public virtual string ReplaceAdInfo(string modelinfo)
        {
            if (Config != null)
            {
                int adprojectid = Config.AdProjectid;
                if(adprojectid>0)
                {
                IAdProjectManage projectmanage = new AdProjectManageBL();
                List<Ewk_adViewForCreate> lists = projectmanage.GetAdProjectDetailForCreate(adprojectid);
                String adimage;
                String href = "";
                if (lists.Count > 0)
                {
                    foreach (Ewk_adViewForCreate item in lists)
                    {
                        if (item.Ad_type == 0)
                        {
                            adimage = "<img src=\"http://www.e-works.net.cn/AdRotators/images/project/" + item.Ad_imageurl + " \" border=0 width=\"" + item.Width + " \" height=\"" + item.Height + "\">";
                            href = "<a href=\"" + item.Ad_url + " \"  target='_blank'>" + adimage + "</a>";
                        }
                        else if (item.Ad_type == 1)
                        {
                            href = "";
                            href += "<object type=\"application/x-shockwave-flash\" width=\"" + item.Width + "\" height=\"" + item.Height + "\" data=\"http://www.e-works.net.cn/AdRotators/images/project/" + item.Ad_imageurl + "\"> <param name=\"wmode\" value=\"Opaque\" />\n";
                            href += "<param name=\"movie\"  value=\"http://www.e-works.net.cn/AdRotators/images/project/" + item.Ad_imageurl + "\" />\n";
                            href += "</object>";
                        }
                        else
                        {
                            href = item.Ad_code;
                        }
                        String oldvalue = "<!--#" + item.Ad_name + "-->";

                        modelinfo = modelinfo.Replace(oldvalue, href);
                    }
                }
                }
            }

            return modelinfo;
        }

      //文章内容信息处理
        public abstract void DealHtmlModelAndCreate(string modelinfo, int topicId, int objectid, string webRootPath);
    }
}


写完了抽象类,大家肯定知道需要写具体的网页生成类来继承它,下面是一个简单的文章列表页面生成类的代码:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using CommTool;

using IDAL.CreatePage;

using Dal.CreatePage;

using EworksCms.Domain;

using EworksCms.Domain.CreatePage;

using Framework.CreatePageHelper;

namespace Framework.CreatePage

{

    public class ArticleSecondCreate : AbstractEworksCreatePage

    {

        public override string GetPageHeadArea()

        {

            string headinfo = ArticleCreateCommMethod.GetArticlesHeadArea();

            return headinfo;

        }

       public override void DealHtmlModelAndCreate(string modelinfo, int topicId, int objectid, string webRootPath)

        {

            //获取文库相关的栏目序号

            List<Ewk_Content_TopicView> allarticles = ContentTopicHelper.ListChildTopicList(11, "48,377,674");

            //获取对应大类,所有的子类数据

            var tempchild = from d in allarticles

                            where d.Content_topic_uid == topicId

                            select d;

            string childtopicids = "";

            StringBuilder sb = new StringBuilder();

            foreach (Ewk_Content_TopicView item in tempchild)

            {

                sb.Append(item.Content_topic_id + ",");

            }

            childtopicids = sb.ToString();

            if (childtopicids.Length > 0)

                childtopicids = childtopicids.Substring(0, childtopicids.Length - 1);

            IArticleSecondListCreate secondcreate = new ArticleSecondListCreate();

            ArticleSecondListCreateData dateinfo = secondcreate.GetArticleSecondListData(topicId, childtopicids);

            //替换掉数据

            //4个排行榜

          下面省去若干行。。。

        }    

    }

}

 这个类继承了上面的抽象类,并复写了抽象类中的虚方法。
至此我们实现了面向对象三大特性中的继承还有多态,但是说好的封装呢?还有可扩展性呢?五大原则都遵循了吗?别急,我们的程序还没完,程序如果写成这个样子,封装性太差,客户程序调用的时候很麻烦,根本不敢拿出来秀。
为了让程序有好的封装性,客户有统一的调用接口,以及满足面向抽象编程、面向接口编程的原则;对修改关闭,对扩展开发的原则,我们给程序加一个辅助类来包装一下程序。代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EworksCms.BL;
using EworksCms.BLInterface;
using EworksCms.Domain;
using EworksCms.Domain.CreatePage;
using EworksCms.Domain.Link;
using EworksCms.BL.Link;
using Framework._2014CreatePage;
using EworksCms.BLInterface.Link;
using CommTool;
 
namespace Framework.CreatePageHelper
{
    public class EworksCreatePageHelper
    {
        public static void CreatePage(EworksCreateTopicConfig config,AbstractEworksCreatePage createpagedetail, int objectid,string webRootPath)
        {
            createpagedetail.Config = config;
            StringBuilder modelinfo = new StringBuilder();
            modelinfo.Append(createpagedetail.GetPageModelContent());//获取模版
 
            modelinfo.Replace("<!--#Header-->", createpagedetail.GetPageHeadArea());
 
            modelinfo.Replace("<!--#Footer-->", createpagedetail.GetPageBottomArea());
            modelinfo.Replace("<!--#SeoTitle-->", createpagedetail.GetSeoTitle());
            modelinfo.Replace("<!--#SeoKeywords-->", createpagedetail.GetSeoKeywords());
            modelinfo.Replace("<!--#SeoDescrption-->", createpagedetail.GetSeoDescrption());
            if (config.WebLinkid > 0)
            {
                //替换掉友情链接的数据
                modelinfo.Replace("<!--#friend-->", GetFriendLinkText(config.WebLinkid));
            }
            string models=createpagedetail.ReplaceAdInfo(modelinfo.ToString());
            createpagedetail.DealHtmlModelAndCreate(models, config.ContentTopicid, objectid, webRootPath);
        }
 
     下面省去若干无关方法与代码。。。
 
    }
}
这个类中最重要的一个方法就是: 
  public static void CreatePage(EworksCreateTopicConfig config,AbstractEworksCreatePage createpagedetail, int objectid,string webRootPath).
       它的第二个参数类型是网页生成方法的抽象类:AbstractEworksCreatePage ,其实就相当于一个接口,客户程序调用的时候可以把自己的网页生成类传递进来,比如生成文章列表页面就可以象下面那样调用:  EworksCreatePageHelper.CreatePage(EworksCreateTopicConfigHelper.GetEworksCreateTopicConfig(id), ArticleListCreate(), 0, SitePathHelper.GetWebSitePhysicalPath() + "\\articles\\");
       有了帮助类以后,程序就有了较好的封装性,系统暴露给外部程序的调用接口形式是一致的,如果你要生成新闻页面,程序还是调用 EworksCreatePageHelper.CreatePage方法,你只要AbstractEworksCreatePage 参数换成生成新闻页面的类就行了。
       至此本程序已经实现面向对象编程的三大特性。
      
 
posted @ 2017-07-31 17:10  无招胜有招  阅读(259)  评论(0编辑  收藏  举报