个人感悟之CMS的精华和糟粕

“神一样的队友”,“猪一样的队友”,“码农”,“工程狮”,“程序猿”,“看山不是山,看水不是水”,吧啦吧啦...

等一等。老码农你想说神马?

额,就是这个...那啥...,哎拖延症人人都有吧,为啥还有那么多毛病没改变呢。

最近啊,盼转正好久了,都快转正了。那对CMS有些自己的看法吧.。这里感谢公司这个平台,这个舞台。感谢队友们的支持和鼓励,希望作为老码农的我,能成为靠谱的队友,

给大伙些正能量和分享些经验,希望大伙少淌坑,为客户为公司多创造一些价值...

下面说说天天面对的CMS的精华和糟粕。

CMS的精华:

  • 1、面向对象思想之封装
  • 2、面向对象思想之继承
  • 3、设计模式的运用
  • 4、接口的运用之解耦
  • 5、泛型(泛型委托)应用
  • 6、玩多线程的姿势好帅
  • 7、IOCP完成端口)的使用
  • 8、牛逼哄哄的AOP面向切面编程
  • 9、动态编译技术的使用
  • 10、反射技术的使用
  • 11、编码生成器
  • 12、ORM和可视化模板设计器等

13、最最牛逼的能力是把前面十多项精华都玩转了,让大伙站在巨人肩上工作...

1、面向对象思想之封装

封装是最基本的面向对象思想之要素,底层处处是封装。写动态代码也应该尽量减少重复代码,该提炼成类的就提炼。

2、面向对象思想之继承

面向抽象编程这个思想是花费了好多年才慢慢正在养成的习惯。感觉做得还不够。架构师必须是偏执狂的,随时在践行各种面向对象的原则,不忘初心才能方得始终. 比如我们常写的流程类是继承了CoreBase,而CoreBase应该打上seale关键字,不允许被直接拿出来实例化。因为CoreBase职责是实现各种模板方法,并把这些方法贯通。面向的是抽象,不是具体的细节(某一工厂的流程). 使用继承就能重复利用基类封装的各种方法。总的来说继承是和封装一起使用的。多态不是必须的规范,代码里面肯定有。这里不单独拿出来说事。

3、设计模式的运用

CodeContext等使用了单例,还有工厂模式比如各种getXXXService等,细看还能发现观察者模式等的使用。觉得都挺应景的。这就是功力啊

4、接口的运用之解耦

接口我认为是用来解耦的最好东西,系统里各种IScanner,IPrinter,IPrintCore...

刚开始我非常惊讶,系统居然是代码和界面是完全分离的。敢情那么多年WINFORM编程都是白瞎,没有人家有追求啊。带来的好处太多了,话说当年我们哪个项目不是拖完控件,然后直接在事件属性里写对应的代码.low得不敢见人啊

5、泛型(泛型委托)应用

namespace ehsure.CMS.Core.Printer
{
    /// <summary>
    /// 用于与打印相关的事件回调
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sender"></param>
    /// <param name="portKey"></param>
    /// <param name="e"></param>
    public delegate void DataPrintHandler<T>(object sender, string portKey, T e);
    /// <summary>
    /// 用于记录状态相关的事件回调
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="portKey"></param>
    /// <param name="data"></param>
    public delegate void DataStatusHandler<T>(object sender,string portKey,T e,bool data);
}

  public interface IScanner
    {
        int BaudRate { get; }
        void Close();
        event DataPrintHandler<TEventArgs<ScanData>> DataReceiving;
        event DataPrintHandler<TEventArgs<PrintData>> DataReceived;
        event FeedInfoHandler FeedInfo;
        bool IsOpen { get; }
        void Open();
}

  这个就不展开说了,其实还应该多使用泛型类来消除重复代码。泛型比较重要的是“约束”能力。

6、玩多线程的姿势好帅

这里说好帅是因为玩多线程需要特别小心一不小心线程同步等异步等技巧真是好高大上的技术啊。需要注意各种细节才能玩得好。具体那里好我也说不清楚,我想这是用看的。

系统里大量使用了IOCP(IoCompletionPort)是WINDOWS系统非常精华的一种模型。听说效率高得没谱,核心是操作系统级别的先进先出队列,反正出队入队都是调各种windows api.

  [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern SafeFileHandle CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, IntPtr CompletionKey, uint NumberOfConcurrentThreads);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool GetQueuedCompletionStatus(SafeFileHandle CompletionPort, out uint lpNumberOfBytesTransferred, out IntPtr lpCompletionKey, out IntPtr lpOverlapped, uint dwMilliseconds);
        [DllImport("Kernel32", CharSet = CharSet.Auto)]
        private static extern bool PostQueuedCompletionStatus(SafeFileHandle CompletionPort, uint dwNumberOfBytesTransferred, IntPtr dwCompletionKey, IntPtr lpOverlapped);

我觉得在.net 2时代有这样的牛叉模型还真是幸福,IOCP还支持多线程并发的。好了这里跑题了。

  

7、IOCP完成端口)的使用

接着说IOCP,在CMS里CoreThreadPool的靓丽身影随处可见。这些应付多线程的利器啊。

    /// <summary>
    /// 自定义线程池类,不依赖.net Queue实现了先进先出处理队列里数据
    /// </summary>
    public class CoreThreadPool : IDisposable
    {
        /// <summary>
        /// 队列元素申明
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private class PoolData
        {
            /// <summary>
            /// 外部要求放入队列的数据
            /// </summary>
            public object Data;
            /// <summary>
            /// 需要执行的命令(Exit/Command(自定义))
            /// </summary>
            public CoreThreadPool.PoolCommand Command;
            public PoolData()
            {
                this.Command = CoreThreadPool.PoolCommand.Exit;
            }
            public PoolData(object data)
            {
                this.Data = data;
                this.Command = CoreThreadPool.PoolCommand.Command;
            }
            public PoolData(CoreThreadPool.PoolCommand cmd)
            {
                this.Command = cmd;
            }
        }
        protected enum PoolCommand
        {
            Command,
            Exit
        }
        protected SafeFileHandle complatePort;
        /// <summary>
        /// 线程池主线程
        /// </summary>
        protected Thread thread;
        protected volatile bool isOpened;
        [method: CompilerGenerated]
        [CompilerGenerated]
        public event Action<object> Exceute;
        [method: CompilerGenerated]
        [CompilerGenerated]
        public event Action<object> ExitExceute;
        /// <summary>
        /// 线程池是否正在运行
        /// </summary>
        public bool IsOpened
        {
            get
            {
                return this.isOpened;
            }
            set
            {
                this.isOpened = value;
            }
        }
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern SafeFileHandle CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, IntPtr CompletionKey, uint NumberOfConcurrentThreads);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool GetQueuedCompletionStatus(SafeFileHandle CompletionPort, out uint lpNumberOfBytesTransferred, out IntPtr lpCompletionKey, out IntPtr lpOverlapped, uint dwMilliseconds);
        [DllImport("Kernel32", CharSet = CharSet.Auto)]
        private static extern bool PostQueuedCompletionStatus(SafeFileHandle CompletionPort, uint dwNumberOfBytesTransferred, IntPtr dwCompletionKey, IntPtr lpOverlapped);
        /// <summary>
        /// 启动线程池的主线程
        /// </summary>
        public void Start()
        {
            isOpened = true;
            if (thread != null)
            {
                throw new Exception("线程池已经是启动状态!");
            }
            complatePort = CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, IntPtr.Zero, 0u);
            if (complatePort.IsInvalid)
            {
                throw new Exception(string.Format("创建IOCP出错!原因是:{0}", Marshal.GetLastWin32Error().ToString()));
            }
            thread = new Thread(new ParameterizedThreadStart(this.Run));
            thread.Start(complatePort);
        }
        /// <summary>
        /// 外部提交数据对象到队列
        /// </summary>
        /// <param name="data"></param>
        public void Post(object data)
        {
            PostData(new CoreThreadPool.PoolData(data));
        }
        /// <summary>
        /// 线程池主线程执行逻辑
        /// </summary>
        /// <param name="CompletionPortID"></param>
        private void Run(object CompletionPortID)
        {
            SafeFileHandle completionPort = (SafeFileHandle)CompletionPortID;
            while (IsOpened)
            {
                uint num;
                IntPtr intPtr;
                IntPtr value;
                //从队列里取出最前面的对象
                CoreThreadPool.GetQueuedCompletionStatus(completionPort, out num, out intPtr, out value, 4294967295u);
                if (num > 0u)
                {
                    GCHandle gCHandle = GCHandle.FromIntPtr(value);
                    CoreThreadPool.PoolData poolData = (CoreThreadPool.PoolData)gCHandle.Target;
                    gCHandle.Free();
                    if (poolData.Command != CoreThreadPool.PoolCommand.Command)
                    {
                        IsOpened = false;
                        break;
                    }
                    RaiseExecute(poolData.Data);
                }
            }
            RaiseExitExecute("线程池已经停止。");
            isOpened = false;
            thread = null;
        }
        /// <summary>
        /// 触发Execute事件
        /// </summary>
        /// <param name="data"></param>
        private void RaiseExecute(object data)
        {
            Exceute?.Invoke(data);
        }
        /// <summary>
        /// 触发ExitExecute事件
        /// </summary>
        /// <param name="data"></param>
        private void RaiseExitExecute(object data)
        {
            ExitExceute?.Invoke(data);
        }
        /// <summary>
        /// 结束线程池主线程
        /// </summary>
        public void Stop()
        {
            PostData(new PoolData(PoolCommand.Exit));
            IsOpened = false;
        }
        /// <summary>
        /// 内部提交数据到线程池队列中
        /// </summary>
        /// <param name="data"></param>
        private void PostData(PoolData data)
        {
            if (complatePort.IsClosed)
            {
                return;
            }
            GCHandle value = GCHandle.Alloc(data);
            PostQueuedCompletionStatus(complatePort, (uint)IntPtr.Size, IntPtr.Zero, GCHandle.ToIntPtr(value));
        }
        public void Dispose()
        {
            if (this.thread != null && this.thread.ThreadState != System.Threading.ThreadState.Stopped)
            {
                this.Stop();
            }
        }
    }

上面代码是我反编译出来的。CMS是封装在dll里了,平常看不到源码的。

/// <summary>
    /// 自定义线程池类,使用ConcurrentQueue实现了先进先出处理队列里数据
    /// </summary>
    public class CoolThreadPool : IDisposable
    {
        protected ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
        protected Thread thread;
        private volatile bool isOpened;
        public bool IsOpened
        {
            get
            {
                return isOpened;
            }
        }

        public event Action<string> Exceute;
        public event Action StopedExceute;
        /// <summary>
        /// 启动线程池的主线程
        /// </summary>
        public void Start()
        {
            if (thread != null)
            {
                throw new Exception("线程池已经是启动状态!");
            }
            thread = new Thread(Run);
            isOpened = thread != null;
            thread.Start();
        }

        /// <summary>
        /// 线程池主线程执行逻辑
        /// </summary>
        private void Run()
        {
            while (isOpened)
            {
                if (queue.Count > 0)
                {
                    string temp = null;
                    queue.TryDequeue(out temp);
                    if (!string.IsNullOrEmpty(temp))
                    {
                        RaiseExecute(temp);
                    }
                    else break;
                }
            }
            isOpened = false;
            thread = null;
            RaiseStopedExceute();
        }

        /// <summary>
        /// 触发Execute事件
        /// </summary>
        /// <param name="data"></param>
        private void RaiseExecute(string data)
        {
            Exceute?.Invoke(data);
        }

        /// <summary>
        /// 触发停止Execute事件
        /// </summary>
        /// <param name="data"></param>
        private void RaiseStopedExceute()
        {
            StopedExceute?.Invoke();
        }

        /// <summary>
        /// 结束线程池主线程
        /// </summary>
        public void Stop()
        {
            PostData(null);
            isOpened = false;
        }

        /// <summary>
        /// 外部提交数据对象到队列
        /// </summary>
        /// <param name="data"></param>
        public void Post(string data)
        {
            PostData(data);
        }

        /// <summary>
        /// 内部提交数据到线程池队列中
        /// </summary>
        /// <param name="data"></param>
        private void PostData(string data)
        {
            queue.Enqueue(data);
        }

        public void Dispose()
        {
            if (this.thread != null && this.thread.ThreadState != System.Threading.ThreadState.Stopped)
            {
                this.Stop();
            }
        }
    }

8、牛逼哄哄的AOP面向切面编程

主程序的权限和界面的各种校验都是使用了各种拦截器。这个由于没有深入研读源码,待以后体会到再分享。

9、动态编译技术的使用

 /// <summary>
        /// 动态编译动态脚本
        /// </summary>
        /// <param name="content">动态脚本对象</param>
        /// <returns>返回程序集实例</returns>
        static Assembly BuildDynamicPrintCore(DynamicScript content)//(DynamicPrinterConfig content)
        {
            CoreBuilder cb = new CoreBuilder();
            cb.Header = header;
            cb.Bottom = bottom;
            cb.UseingText = content.UsingText;
            cb.ReferenceText = content.ReferenceText;
            return cb.Compile(content.Script);
        }
        /// <summary>
        /// 动态编译动态脚本
        /// </summary>
        /// <param name="content">动态脚本对象</param>
        /// <returns>返回程序集实例</returns>
        static Assembly BuildDynamicPrintCore(DynamicPrinterConfig content)
        {
            CoreBuilder cb = new CoreBuilder();
            cb.Header = header;
            cb.Bottom = bottom;
            cb.UseingText = content.UsingText;
            cb.ReferenceText = content.ReferenceText;
            return cb.Compile(content.Script);
        }
        /// <summary>
        /// 动态脚本引用的程序集头
        /// </summary>
        const string header = @"
using System;
using System.Collections.Generic;
using System.Threading;
using System.Timers;
using EES.Common;
using EES.Common.Data;
using ehsure.CMS.Core.Card.DI;
using ehsure.CMS.Core.Card.DO;
using ehsure.CMS.Core.Codes;
using ehsure.CMS.Core.Printer;
using ehsure.CMS.Core.Printer.Saver;
using ehsure.CMS.Core.Scanner;
using ehsure.CMS.CoreData;
using ehsure.CMS.CoreData.Common;
using ehsure.CMS.CoreData.Config;
using ehsure.CMS.CoreData.Exceptions;
using ehsure.CMS.Core;
using System.Text;
using ehsure.CMS.Common;
using ehsure.CMS.Common.Config;
using System.Linq;
using System.Net.Sockets;
using EES.Common.Query;

using System.Text.RegularExpressions;
namespace ehsure.CMS.Core
{
    public class DynamicPrintCore : CoreBase
    {
        public DynamicPrintCore()
            : base()
        { }

        public static IPrintCore CreateNew()
        {
            return CoreBase.CreateNew(typeof(DynamicPrintCore));
        }

";

11、编码生成器

这是生码必须要使用的模块。这么的人性化也是颠覆了我的认知。想起来在某项目里写的防伪码生成器真是比这个差远了,不好意思见人啊。

12、ORM和可视化模板设计器等

NH,EF等ORM都有用过,但是CMS使用的ORM还是非常佩服,在.net 2时代能弄出来如此像NH,linq的东西还有代码生成器。表示惊为天人,叹为观止。

后记

写文章还挺费时间,关于糟粕我打算另写一篇吧。太长看起来费劲。这个糟粕我还需要收集呢,也许看到的精华有点多,但是希望最终要吸收这些精华,弃糟粕,在CMS代码江湖里贡献一份力量。谢谢大家!

时间: 2024-10-29 14:26:50

个人感悟之CMS的精华和糟粕的相关文章

【转载】转载武汉一名学长给师兄师妹的信

--下面是声明-------------------------------------------------- 这是一篇乱写的博文,不允许转载,写出来只是因为想写所以写了 --声明结束---------------------------------------------------- --下面是正文-------------------------------------------------- 链接:http://blog.sina.com.cn/s/blog_4aec2292010

在知识管死的道路上裸奔

   T公司做CPC已经7年了,号称是囊括了PDM.KM.CPC(产品协同商务)的CPC产品,进去用过后发现不过是鸡肋,里面似乎PDM.KM.CPC啥都有点,但却又啥都不像不地道.暂且先说说知识管理吧,不过是一个类VSS的文件夹管理软件加上文件夹的权限管理即可号称知识管理来招摇撞骗,其结果是不明就里的T公司据说陷在知识的海洋里了,不能搜索.不能识别知识.不能为员工所用,结果全民皆兵的"建档伟业"从文档创建的那一刻起,这份知识就注定寿终正寝了!公司S总戏称为白菜萝卜都可进的图书馆! 所以

男神女神配 社区交友网 —— 之 主页 详细解说

一.项目背景 1. 开发平台.开发工具 (1)后台数据库采用:MySQL Workbench 6.1 CE. (2)代码编写平台采用:Eclipse Java EE IDE for Web Developers:HBuilder:eclipse:IntelliJ IDEA 14.1.1. (3)主要插件:jdk1.6.0_10:mysql-connector-java-5.1.30-bin.jar:apache-tomcat-7.0.54:SpringExample03:apache-maven

C语言之数据类型

---恢复内容开始--- 在C语言中我们的数据类型分为以下几大类: (1)基本数据类型:int, float,double,char,_Bool(C99中新加的),枚举enum: 很多朋友对于enum被定义为是基本类型可能会有些迷惑,但是我们都知道枚举类型的特殊之处就是总能把数据变化为整形数据, 我们可以认为枚举就是一种特殊定义过的整形组合. (2)构造数据类型:数组,结构体(struct),共用体(union) 1.数组的基本格式:数据类型  数组名 [数组size] :我们可以这样理解它:数

JavaScript的一点简介(注:本文诸多观点源于JavaScript高级程序设计,如有侵权,立即删除)

JavaScript是一门最易让人误解的语言,该语言中精华与糟粕并存(可能比一般语言的这个比例要大一些):但“千淘万漉虽辛苦,吹尽黄沙始到金”,层层面纱下是易用灵活.优雅轻灵的内在.很久以前,JavaScript被当做是玩具语言,直到AJAX的出现,直到V8引擎的易用:这种局面已经改变. JavaScript诞生于1995年(那时我还很小):一个叫Brendan Eich的人设计了这种语言.他就职于Netscape公司,他说服了老总要开发这种语言.然而仅用了10天,10天.这门语言最初是用于解决

结对项目——博客记录(附加题)

结对项目内容:http://www.cnblogs.com/jiel/p/4830912.html 结对成员:康家华,马腾跃(http://www.cnblogs.com/summerMTY) [附加题]第四阶段目标 - 界面模块,测试模块和核心模块的松耦合. 对于这个附加题,我们小队(A)决定和刘乾小队(B)的模块进行交换,于是在拿到对方的代码时,我们立刻就傻眼了. 不是说对方写的很差,相反,B小队的代码有刘乾的保证,质量很高.让我们傻眼的是因为我们的想法不是完全相同的,而我们设计的接口的要求

9种新思想

672. 2011年11月8日 - Lisp语言诞生的时候就包含了9种新思想.其中一些我们今天已经习以为常,另一些则刚刚在其他高级语言中出现,至今还有2种是Lisp独有的. [2016-05-01 15:35:48]673. (8) 代码使用符号和常量组成的树形表示法. [2016-05-01 15:36:21]674. (9) 无论什么时候,整个语言都是可用的. [2016-05-01 15:36:35]675. Lisp语言古怪倒不是因为它的语法很古怪,而是因为它根本没有语法,程序直接以解析

框架成为新的编程语言的7种理由

感谢强大的工具.对速度的需求.和编程本身的变迁,下一次乏味的战争将终结于框架 API.而非语法. AD: 在 1980 年代,掀起一场乏味战争的最简单方法,就是赞扬你钟爱的编程语言是最棒的.C.Pascal.Lisp.Fortran?程序员们花费数个小时来详细解释关于精巧制作一条 if-then-else 语句的特定方式为什么优于你的方式. 那是过去的事情了.今天,涉及语法和结构的战争基本结束了,因为世界已经汇总了一些简单标准.在 C.Java 和 JavaScript 里,分号.花括号等之间的

front client

欢迎来到BOOTCAMP.在这里,我们将全周期生活在JavaScript实战编码的环境下完成Web技能的学习.一起穿越JavaScript开发中危险重重的“编程陷阱”和“开发沼泽”,才能完成Web开发周期“实战拉练”项目的各项测试和考核.要想完成这项光荣的使命,我们必须: • 熟练使用各种“生存工具”:如JavaScript调试工具.单元测试工具.合并与压缩.IDE开发环境以及其插件的使用; • 独立搭建JS下的持续构建开发环境: • 掌握各种编程实践的技法.这包括:TDD.BDD...各种实战