原型模式(Prototype Pattern)-创建型模式第五篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

距离发布上篇软件设计模式文章《建造者模式》稍稍地已经过去两个多月,今天来谈一下第五个创建型模式,这也将是最后一个创建型模式——原型模式(Prototype Pattern)。

定义:

Prototype模式,通过将对象自身进行复制来创建新的对象。多么简单的定义,该模式也很简单。

解决的问题:

  1. 在运行时如何动态创建一个对象的副本

怎么去解决:

  1. 通过定义一个含有Clone方法的Prototype接口
  2. 具体的实现类通过继承Prototype接口来创建自身的复制品

UML:

Continue reading “原型模式(Prototype Pattern)-创建型模式第五篇”

建造者模式(Builder Pattern)-创建型模式第四篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

也许得写一个段落放在文章的开头才会显得整篇没那么单调,我想写些什么,但指头落下的那一刻便忘了。简言之,设计模式犹如人生。好吧,也许这就算一个简单的开头,请让我们来看今天的主角,建造者模式(Builder Pattern),我不确定中文称它建造者模式是否准确,偶尔也会看到有人称其构建者或生成器模式。

定义:

Builder模式,通过将对象的构造过程与其本身分离开来,以简化复杂对象的创建过程,并且能够实现相同的构造过程可以创建不同的对象。

解决的问题:

  1. 如何通过简单的方式创建一个复杂的对象
  2. 如何通过相同的过程来创建类的不同实例

怎么去解决:

  1. 在一个独立的Builder对象中去创建和组装复杂对象的各个部分
  2. 通过对Builder的抽象,在创建复杂对象的过程中委托给具有相同接口的不同Builder实现,以达到相同的过程创建不同的对象

UML:

Continue reading “建造者模式(Builder Pattern)-创建型模式第四篇”

单例模式(Singleton Pattern)-创建型模式第三篇

  1. 《设计模式》系列序——写给未来的自己
  2. 工厂方法模式(Factory Method)-创建型模式第一篇
  3. 抽象工厂模式(Abstract Factory Pattern)-创建型模式第二篇
  4. 单例模式(Singleton Pattern)-创建型模式第三篇
  5. 建造者模式(Builder Pattern)-创建型模式第四篇
  6. 原型模式(Prototype Pattern)-创建型模式第五篇
  7. 装饰者模式 (Decorator Pattern)-结构型模式第一篇
  8. 组合模式 (Composite Pattern)-结构型模式第二篇
  9. 适配器模式 (Adapter Pattern)-结构型模式第三篇
  10. 代理模式 (Proxy Pattern)-结构型模式第四篇
  11. 桥接模式 (Bridge Pattern)-结构型模式第五篇

人坚持一件事情是挺难的,工作如此、生活如此、友情如此、亲情如此、爱情亦如此,如果有人能够坚持真心待你,请珍惜他或她。闲话不多说,让我们来看今天的主角,单例模式(Singleton Pattern)。

解决的问题:

  1. 如何确保一个类在应用程序生命周期中只产生一个对象。例如外观模式(Facade Pattern)往往就需要结合Singleton模式来使用,在一个应用中Facade模式通常只需存在一个实例
  2. 如何能让对象状态在整个应用程序生命周期内被使用,Singleton模式相对全局变量在某些语言中可能存在如下优势:
    • Singleton模式可以延迟初始化和内存分配,在某些语言中(比如C++)全局变量在应用程序初始化期间内存便被分配

怎么去解决:

就像其它所有模式一样,实现Singleton模式的方法也有多种,下面例举其中一种方法。

  • 通常我们可以为类定义一个公共的静态方法或属性,并在该方法或属性体中进行类的实例化,倘若发现已经存在实例化的对象,那么就直接返回这个已经存在的对象。

UML:

Continue reading “单例模式(Singleton Pattern)-创建型模式第三篇”

闲扯两句,浅谈C++编译流程

世事总是很奇秒,难道不是吗?世间,每个人都在不断改变着,也许过程坎坷不平,也许路途千回百折。不过最终好在,我们都还坚持着。

又是一年最好时光,也许应该放下思绪,整理行囊,来一次遇见自己的旅行,就像那首歌所唱的一样,“几次真的想让自己醉,让自己远离那许多恩怨是非,让隐藏已久的渴望随风飞,忘了我是谁”,但同样曲中那句“男人若没人爱,多可悲”也点明了旅途中一个人是孤独的。

不扯了,还是想一想今次染个什么颜色的头发吧:)

今天来谈一谈C++的一般编译流程(前面日志中不确定是否已提到斯最近因工作需要在研究C++)。

通常,这里只说通常,将C++源代码编译成可执行程序,需要经历4个步骤;同样是通常,编译软件我们会选择g++。

第1个步骤:预处理器(preprocessor)将头文件(.h)内容复制到源文件(.cpp)中,生成宏代码,替换通过#define定义的常量,最终生成新源文件

第2个步骤:通过编译器(compiler)将第1个步骤所生成的新源文件,编译成指定平台的汇编语言(默认文件名后缀.s)

第3个步骤:汇编器(assembler)将第2个步骤生成的汇编代码再编译成指定平台的目标代码(即机器代码,默认文件名后缀.o)

第4个步骤:链接器(linker)将第3个步骤生成的那些目标代码文件进行链接,以最终生成可执行文件(机器代码)

说的太简单,不够活泼生动形象,举个栗子。 Continue reading “闲扯两句,浅谈C++编译流程”

POSIX

This post is copied from Wikipedia.

The Portable Operating System Interface (POSIX)[1] is a family of standards specified by the IEEE Computer Society for maintaining compatibility between operating systems. POSIX defines the application programming interface (API), along with command line shells and utility interfaces, for software compatibility with variants of Unix and other operating systems.[2][3]

Name

Originally, the name “POSIX” referred to IEEE Std 1003.1-1988, released in 1988. The family of POSIX standards is formally designated as IEEE 1003 and the international standard name is ISO/IEC 9945.

The standards emerged from a project that began circa 1985. Richard Stallman suggested the name POSIX to the IEEE instead of former IEEE-IX. The committee found it more easily pronounceable and memorable, and thus adopted it.[2][4]

Overview

Unix was selected as the basis for a standard system interface partly because it was “manufacturer-neutral”. However, several major versions of Unix existed—so there was a need to develop a common denominator system. The POSIX specifications for Unix-like operating systems originally consisted of a single document for the core programming interface, but eventually grew to 19 separate documents (POSIX.1, POSIX.2, etc.).[5] The standardized user command line and scripting interface were based on the UNIX System V shell.[6] Many user-level programs, services, and utilities (including awk, echo, ed) were also standardized, along with required program-level services (including basic I/O: file, terminal, and network). POSIX also defines a standard threading library API which is supported by most modern operating systems. In 2008, most parts of POSIX were combined into a single standard (IEEE Std 1003.1-2008, also known as POSIX.1-2008). Continue reading “POSIX”

一个查找到指定文件然后进行删除的工具

上上个周末,Maybe,记不清了,也许是上上上个周末,总之那会儿我在听英语,但那其实就是催眠曲,反正很快就靠着椅子睡着了。而后很自然地做起了美梦,梦里却为那台办公笔记本电脑犯着愁,为啥愁?磁盘空间又满了,是完完整整地满了,1B都插不进去的那种。为了释放出可怜的磁盘空间,哪怕一点点,这1年里,可谓想了不少招数,这次似乎真的无计可施了。那该怎么办?一觉被吓醒。

眯着眼睛想了想,也许是有些文件很大,或许可以找到它们,删除一些来释放一些空间。

于是乎坐起来,趁着阳光还不错,便写了这个工具。它主要提供以下功能:

  1. 输入字符串去搜索符合文件名规则的文件
  2. 输入文件大小去搜索大于该Size的文件
  3. 查找的结果会被保存在SQLite数据库中
  4. 可以暂停查找,也可以继续
  5. 对查找结果可以再进行排序,方便二次筛选
  6. 选中某些查找结果进行删除操作
  7. 如果在查找和删除的过程中发生了异常,比如资源被占用而无法删除,可以通过Messages窗口查看

之前发布的工具很少去写文字来表达设计上的优势和缺点,以后可能会多写一些设计思路。这个工具在设计时,主要考虑了以下问题:

  1. 由于针对文件系统的操作通常是比较消耗计算机资源的,所以考虑了暂停功能,这样当需要优先在其它应用下操作时,可以先暂停
  2. 有的时候我们会查找出大量的文件需要去甄选,可能一时半会儿难以做完,所以考虑了将查找的结果保存到SQLite数据库中,这样下次可以直接打开上次的查找结果继续甄选
  3. 为了面向更多的操作系统,核心的代码都基于.Net Standard编写,这意味着可以方便地运行在多种操作系统上(当前仅表示层使用WinForm实现)
  4. 考虑只是个简单的工具,Layer的划分比较简单随意,但在设计时独立了Business Layer,也解除了对DA的依赖,为未来可能的独立化该组件提供捷径。
  5. 考虑查找的过滤条件未来可能会继续增加,抽象了过滤条件组合,能够很方便添加新的过滤规则

Continue reading “一个查找到指定文件然后进行删除的工具”

新年前最后一弹,发布一个抽奖工具

在正式开始介绍这个工具之前,先来讲一下这个工具的历史吧,唉,又勾起满满的回忆:)

它的第一个版本,如果没有记错的话,应该诞生在2010年冬天,记得当时所在公司的驻地是苏大冠名的一家科技产业园,产业园公司邀请所有园内企业参加那年的年终Party,晚会过程中会穿插抽奖环节,由于产业园里很多企业是做IT有关的产品与服务,所以希望抽奖环节能否弃用传统的抽奖箱方式,于是乎基于友情赞助,便写了这个工具的第一个版本。

紧接着下来的第二年,一个朋友向我要了这个工具,还提了一个新需求,能不能添加一个作弊功能,简单来说就是让某人必中某等奖,另外由于人员名单是现场签到输入,界面会被同时显示在投影仪上,所以作弊并不太方便,进而希望能不能作弊不被人看见?于是乎,便又增加了一个基于WML语言编写的WAP网站(因为那时候手机都支持WML,支持HTML的智能手机还并不多),以让作弊者使用手机来操作某人必中某等奖。该功能在现在的版本中,已经被拿掉,作弊实在太猥琐。

前几天机缘巧合之下,听说某公司会进行一场旧产品内部拍卖,于是想起了这个工具,便从尘封多年的笔记本中找出了源代码,顺便也升了个级。

好了,故事说完,谈正事,先说说工具大概提供的功能吧:

  1. 支持2种数据库,SQL Server和SQL CE,默认使用的是SQL CE,程序在首次运行时会自动创建数据库结构
  2. 自定义奖品名称,也就是一等奖,二等奖啥的
  3. 新建或修改一场抽奖活动,能够编辑此次活动包含哪些奖品和数量,以及允许指定每个人最多允许中奖几次(通常设置为1,即这个人中奖1次后,在这场活动中便不会再中奖)
  4. 单条输入或批量导入这场活动有哪些人参加,也就是说只有这些人可以参与抽奖
  5. 进行抽奖:
    1. 这批抽几个(假设三等奖100个,在抽奖时可以输入这批只抽20个)
    2. 从本场活动的人员名单中随机抽取
  6. 领奖,将人员勾选中以表示此人已经领取了奖品

Continue reading “新年前最后一弹,发布一个抽奖工具”

发布一个新工具Ping,兼年终总结

这篇文章只是草稿,后面应该会有增减。

一年一年又一年,转眼就快到新年。

好长时间没有写日志了,也许是懒了,也许是事情太多,总之理由是可以找出一堆一堆又一堆的。回想一下设计模式系列已经很久没有更新了,记得当初是打算每个月写一篇的,汗颜啊。

写这篇日志有两个目的,一是最近写了个小工具,用来测试主机是否在线的;二是想对过去一年作一个简单的总结。

先来总结吧,这里只说好的,只说知识技能上的成长,不说坏的,也不说情感金钱之类的。当然不是没有坏的,相反,而是坏的实在太多了,不敢列,不想列,担心会抽自己几巴掌。

  1. 复习了TypeScript,PowerShell, Bash,Python,C++等编程语言,虽然说离开软件行业已近2年,但是你懂的,有一种习惯叫兴趣,也有一种工作方式叫痛并快乐着。下面分别简单说一下这几种语言:
    1. TypeScript是微软开发的面向对象的脚本语言,支持鼓励强类型编程,实现了ECMAScript 标准,可以轻松编译出Javascript代码,从而运行在Javascript引擎上。当下很多流行的UI框架都有推荐使用TypeScript作为开发语言,比如Angular 2, Vue, Dojo等,但是随着Javascript版本的不断更新,以及相关引擎的支持,似乎越来越不需要TypeScript了。
    2. PowerShell是微软开发的Windows下的Shell脚本语言,我个人认为它的最大一个特点是可以使用.Net Framework,并且它也拥有通常高级语言所包含的语法(它的语法也比Bat要优雅的多,站在我的角度我优先会使用PowerShell而不是Bat,除非环境有所限制),所以理论上它可以实现任意功能。
    3. Bash是很多Linux系统上的默认Shell环境,它拥有比较完整的编程语言语法系统。个人认为,如果想利用好Linux系统,简化繁琐的工作,那么Bash是必修的课程。
    4. Python,说起这个语言,就我个人而言很是曲折,最早接触它的时候,2.3版本才刚刚发布,谁曾想到现在它会这么火爆,拥有丰富的API、工具、框架。想拿高薪,你得会Python,毕竟在Big Data, Cloud, AI等领域它最为抢眼。
    5. C++,整个人生道路上,我学的第一门语言就是它(不是C,我直接自学的C++),虽然从来没有正式地使用它做过项目,但实事求是的讲,在后来整个工作学习的道路上,它不断的启发着我,这次因为工作的原因,又重新温习了一遍,感叹前人真是牛逼。
  2. PLC。我他么也没想到,以前一个搞软件的,会去学习PLC,只能解释成博爱吧。关于PLC,我顶多算入了个门,简单一句话,它还是挺有意思的。不过我想随着技术的不断发展,基于Linux等平台的高级语言编程才是大势,比如基于Andorid,Windows loT等,另外像西门子这么贵的PLC设备也终就会被Raspberry Pi这种小巧便宜的设备所取代。
  3. 英语。说到这个,虽然说到了痛点,但是比去年还是有了些进步,偶尔讲两句也可以。

好吧,总结就总结到这里,后面如果想起了别的再加上来。下面来说说最近写的一个小工具。

工具的名称叫Ping,顾名思义,和我们经常使用的命令Ping有着相似的功能,即发送ICMP数据包给指定主机,来侦测远端主机是否在线,判断与远端主机之间的网络连接状况等。这个工具的特别之处是可以批量侦测大量主机,结合多线程来快速诊断网络状况。并且该工具基于.Net  Core编写,所以能够跨平台运行,无论是Windows、Linux还是MacOS。下面的截图基于Debian 9.5 + .Net Core 2.1。 Continue reading “发布一个新工具Ping,兼年终总结”

STA and MTA

这篇文章摘自网络。

本文讨论在.NET中使用进程内COM组件时的公寓模型,以一个示例直观演示STAThread和MTAThread的作用和区别。

1. COM中的公寓

1.1 基本规则

公寓是COM组件的运行环境,日常生活中公寓是用来住人的,COM中的公寓是用来住COM组件的对象的,每个COM对象必须且只能位于一个公寓中:单线程公寓(STA)或多线程公寓(MTA)。

每个进程可以有0或多个STA。

每个进程可以有0或1个MTA。

一个线程只能关联到一个公寓。因此所有关联到MTA的线程都是关联到进程唯一的一个MTA。

本线程访问与本线程关联的STA中的COM对象不需要列集,直接访问。

其他线程对STA中的COM对象的访问需要列集(marshal),通过列集,自动实现了多线程访问下的同步

所有线程对MTA中的COM对象的访问不需要列集,直接访问,需要COM组件自身实现多线程下的同步

(列集就是将函数调用序列化,实现跨边界调用,在Windows中通常是通过消息机制实现。在COM中RPC就是列集,在WinForm中Control.Invoke就是一种列集,Remoting也是列集,WCF也是列集,最近流行的RESTfull也是。。。)

1.2 公寓类型匹配

一个COM对象所属的公寓,由两个地方的配置确定:组件公寓模型客户端线程公寓模型

  1. 组件公寓模型是在组件注册到注册表时设定,通过组件公寓模型,组件声明自己可以住在什么样的公寓里。可选项包括:Apartment,Free和Both。Apartment,我只能住在单线程公寓中;Free,我只能住在多线程公寓中;Both,我随意,单线程公寓或多线程公寓都可以。
  2. 客户端线程公寓模型就是线程的公寓模型,表示当前线程提供什么样的公寓。可选项包括:单线程公寓(STA)或多线程公寓(MTA),也就是本文所讨论的STAThread和MTAThread。

下表列出了组件对象最终会住在什么公寓中的组合表:

客户端线程公寓模型 \ 组件公寓模型  Apartment Free Both
STA STA MTA STA
MTA STA MTA MTA

如果组件公寓模型为Apartment,不管客户端线程公寓模型是什么,组件最后都住在STA中,因为组件说了“我只能住在单线程公寓中”。如果当前线程是MTA,COM库会后台创建一个STA来放该组件的对象。

如果组件公寓模型为Free,不管客户端线程公寓模型是什么,组件最后都住在MTA中,因为组件说了“我只能住在多线程公寓中”。如果当前线程是STA,COM库会检查当前进程的MTA有没有创建,没有就创建进程的MTA,然后将组件的对象放在MTA中。

如果组件公寓模型为Both,组件最后都住在与当前线程关联的公寓中,如果当前线程是STA,它就住在STA中;当前线程是MTA,它就住在MTA中。本文中,我们会创建一个并注册一个Both类型的组件,然后分别在STA和MTA中创建该组件的对象。

1.3 .NET中设置客户端线程公寓模型 

在.NET中使用COM组件时,需要设置线程的公寓模型。

在.NET中可以通过STAThread和MTAThread属性来设置主线程的公寓类型, 通过Thread.SetApartmentState可以设置工作线程的公寓类型。

对于WinForm或WPF应用程序,主线程的公寓模型必须为STA,因为用户界面对象都不是线程安全的。

对于控制台应用程序,主线程的公寓模型可以随意设置,为了方便,我们用控制台应用程序来演示。(用WinForm也完全可以演示,只是需要在工作线程中创建组件的对象。)

2. 一个简单的COM组件

为了演示单线程公寓和多线程公寓的区别,我们用ATL实现定义一个简单的COM组件SimpleCom,该组件包含一个返回字符串的方法Hello,返回的字符串分三步合成,每步之间通过Consume方法来消耗较长CPU周期,确保Hello不会在操作系统的一个时间片内被执行完成,保证Hello函数被并发执行,以达到演示的效果。代码如下: Continue reading “STA and MTA”