首先向关注过我这个系列的同修们说声 对不起昨天朋友孩子满月,去喝酒喝挂了,回家本想小睡一会又起来写代码,一不小心醒来就是今天早上了。真是非常抱歉,为了符合原计划及帖子标题,这个帖子是补发昨天的,今天的晚一点贴上。昨天在论坛看到有人提出MDI界面中控制子窗体不要重复显示的问题这立刻让我想到了最常用也是最简单最容易理解的一个设计模式 单例模式何为 单例模式 ?故名思议 即 让 类 永远都只能有一个实例。由于 示例代码 比较简单 我也加了注释,这里就不在赘述以下是通过 单例模式 实现的控制mdi子窗体实例化的代码mdi父窗体namespace 单例模式
{
public partial class frmMdiParent : Form
{
public frmMdiParent()
{
InitializeComponent();
} private void mnuItemOpenMdiChildren_Click(object sender, EventArgs e)
{
//客户代码,只需要管调用,不需要管实现,符合封闭-开放原则
frmChildren.GetInstance().Show();
} }
}
mdi子窗体
namespace 单例模式
{
public partial class frmChildren : Form
{
private frmChildren()
{
InitializeComponent();
} //声明一个静态的自己类型的变量
private static frmChildren _objFrmChildren = null; //构造方法改为私有,使外部代码无法通过 new 来实例化
private void frmChildren_Load(object sender, EventArgs e)
{ } //外部代码通过这个方法来获取 类 的实例 以代替类构造函数功能
public static frmChildren GetInstance()
{
//判断实例是否存在,不存在则调用构造方法
if (_objFrmChildren == null || _objFrmChildren.IsDisposed)
{
_objFrmChildren = new frmChildren();
_objFrmChildren.MdiParent = frmMdiParent.ActiveForm;
}
return _objFrmChildren;
}
}
}
{
public partial class frmMdiParent : Form
{
public frmMdiParent()
{
InitializeComponent();
} private void mnuItemOpenMdiChildren_Click(object sender, EventArgs e)
{
//客户代码,只需要管调用,不需要管实现,符合封闭-开放原则
frmChildren.GetInstance().Show();
} }
}
mdi子窗体
namespace 单例模式
{
public partial class frmChildren : Form
{
private frmChildren()
{
InitializeComponent();
} //声明一个静态的自己类型的变量
private static frmChildren _objFrmChildren = null; //构造方法改为私有,使外部代码无法通过 new 来实例化
private void frmChildren_Load(object sender, EventArgs e)
{ } //外部代码通过这个方法来获取 类 的实例 以代替类构造函数功能
public static frmChildren GetInstance()
{
//判断实例是否存在,不存在则调用构造方法
if (_objFrmChildren == null || _objFrmChildren.IsDisposed)
{
_objFrmChildren = new frmChildren();
_objFrmChildren.MdiParent = frmMdiParent.ActiveForm;
}
return _objFrmChildren;
}
}
}
下面是我的抽象工厂模式:(请指教)
http://v.youku.com/v_show/id_XMjYwNjE3NDA4.html
大量运用了 lambda 表达式,所以要认真看。为了简化,我取消了扩展方法的使用(因为扩展方法是为了演示装饰模式的,事实上用不到)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Employee e = new Employee("周润发");
Employee e1 = new Employee("刘德华"); e.Salary.加上("基本工资", 6000).
加上("出勤奖", 300).
加上("清凉补贴", 200).
参照("基本工资").加上("浮动奖励 10%", x => x * 0.1).
在总数的基础上加上("董事长奖金 15%", x => x * 0.15).
加上("新年/平时补贴", () =>
{
if (DateTime.Now.Month == 1)
return 1000;
else
return 500;
}).
参照("基本工资", "浮动奖励 10%").扣除("押金 (基本工资和浮动奖励的5%)", (x, y) => (x + y) * 0.05).
扣除("水电扣除", 100); e1.Salary.加上("基本工资", 4000).
加上("出勤奖", 300).
在总数的基础上加上("董事长奖金 25%", x => x * 0.25).
加上("岗位津贴", 2000).
加上("清凉补贴", 200).
扣除("水电扣除", 120); e.DisplaySalary();
e1.DisplaySalary();
}
} class Employee
{
public string Name { get; set; }
public Employee(string name) { Name = name; } private readonly Salary _salary
= new Salary(); public Salary Salary { get { return _salary; } } public override string ToString()
{
return Name;
}
} static class EmployeeHelper
{
public static void DisplaySalary(this Employee employee)
{
Console.WriteLine(String.Format("{0}\n{1}", employee.Name, employee.Salary));
}
} public class Salary
{
private class SalaryItem
{
public bool Add { get; private set; }
public Func<double, double> Calc { get; private set; }
public string Description { get; private set; }
public bool AfterCount { get; private set; }
public SalaryItem(bool add, double calc, string description)
{
Description = description;
Calc = (x) => calc;
Add = add;
AfterCount = false;
}
public SalaryItem(bool add, Func<double, double> calc, string description)
{
Description = description;
Calc = calc;
Add = add;
AfterCount = true;
}
} public class RefSalary
{
private Func<Salary> Salary; private double? Ref1 { get; set; } private double? Ref2 { get; set; } public RefSalary(double RefValue, Func<Salary> GetSalary)
{
Ref1 = RefValue;
Salary = GetSalary;
} public RefSalary(double RefValue1, double RefValue2, Func<Salary> GetSalary)
: this(RefValue1, GetSalary)
{
Ref2 = RefValue2;
} public Salary 加上(string description, Func<double, double> calc)
{
return Salary().加上(description, calc(Ref1.Value));
} public Salary 加上(string description, Func<double, double, double> calc)
{
if (!Ref2.HasValue) throw new Exception("参数不足!");
return Salary().加上(description, calc(Ref1.Value, Ref2.Value));
} public Salary 扣除(string description, Func<double, double> calc)
{
return Salary().扣除(description, calc(Ref1.Value));
} public Salary 扣除(string description, Func<double, double, double> calc)
{
if (!Ref2.HasValue) throw new Exception("参数不足!");
return Salary().扣除(description, calc(Ref1.Value, Ref2.Value));
}
} private List<SalaryItem> Salaries { get; set; } public Salary() { ResetEmployeeSalary(); } public void ResetEmployeeSalary() { Salaries = new List<SalaryItem>(); } public Salary 加上(string description, double calc)
{
Salaries.Add(new SalaryItem(true, calc, description));
return this;
}
public Salary 加上(string description, Func<double> calc)
{
Salaries.Add(new SalaryItem(true, (x) => calc(), description));
return this;
}
public Salary 在总数的基础上加上(string description, Func<double, double> calc)
{
Salaries.Add(new SalaryItem(true, calc, description));
return this;
}
public Salary 扣除(string description, double calc)
{
Salaries.Add(new SalaryItem(false, calc, description));
return this;
}
public Salary 扣除(string description, Func<double> calc)
{
Salaries.Add(new SalaryItem(false, (x) => calc(), description));
return this;
}
public Salary 在总数的基础上扣除(string description, Func<double, double> calc)
{
Salaries.Add(new SalaryItem(false, calc, description));
return this;
} public RefSalary 参照(string RefName)
{
var val = Salaries.Where(x => x.Description == RefName).Single();
if (val == null) throw new Exception("参照项不存在!");
double refval = 0;
if (val.AfterCount == true) throw new Exception("参照项不能在求和后得出!");
refval = (val.Add ? 1 : -1) * val.Calc(0);
return new RefSalary(refval, () => { return this; });
} public RefSalary 参照(string RefName1, string RefName2)
{
var val1 = Salaries.Where(x1 => x1.Description == RefName1).Single();
if (val1 == null) throw new Exception("参照项不存在!");
double refval1 = 0;
if (val1.AfterCount == true) throw new Exception("参照项不能在求和后得出!");
refval1 = (val1.Add ? 1 : -1) * val1.Calc(0); var val2 = Salaries.Where(x2 => x2.Description == RefName2).Single();
if (val2 == null) throw new Exception("参照项不存在!");
double refval2 = 0;
if (val2.AfterCount == true) throw new Exception("参照项不能在求和后得出!");
refval2 = (val2.Add ? 1 : -1) * val2.Calc(0); return new RefSalary(refval1, refval2, () => { return this; });
} public double Count
{
get
{
var items = (from s in Salaries where s.AfterCount == false select s).ToList();
double result = 0;
items.ForEach(item => result += (item.Add ? 1 : -1) * item.Calc(0));
return result;
}
}
public double Value
{
get
{
double count = Count;
var items = (from s in Salaries where s.AfterCount == true select s).ToList();
double result = count;
items.ForEach(item => result += (item.Add ? 1 : -1) * item.Calc(count));
return result;
}
} public override string ToString()
{
double count = Count;
StringBuilder sb = new StringBuilder("工资明细:\n");
var items1 = (from s in Salaries where s.AfterCount == false select s).ToList();
items1.ForEach(item => sb.AppendLine("\t" + item.Description + ":\t" + Convert.ToString((item.Add ? 1 : -1) * item.Calc(count))));
sb.AppendLine("\t小计:\t" + Convert.ToString(count));
var items2 = (from s in Salaries where s.AfterCount == true select s).ToList();
items2.ForEach(item => sb.AppendLine("\t" + item.Description + ":\t" + Convert.ToString((item.Add ? 1 : -1) * item.Calc(count))));
sb.AppendLine("\t实发:\t" + Convert.ToString(Value));
return sb.ToString();
}
}
}
http://v.youku.com/v_show/id_XMTI5MzA4NDUy.html
员工 张学友 = new 员工()
张学友.是一个("工人").享受(二级工待遇)
从月份(5).开始().每一个(工人 => 工人.工资.增加(x => x * 0.1))有100个工人要处理和有10亿个工人要处理,实现能相同?
这段代码1个人本地访问、100个人局域网访问和1亿个人互联网访问,又能实现成一样啊?
软件开发中,代码不过是一小部分,数据、程序、硬件、文档、人代码能占多大的比重呢?
代码结构再好,数据结构重要不、硬件结构重要不、文档重要不。
那个语言能号称,写一份代码适应任何数据结构、硬件结构好,我们就算抛开这些不谈,就你这么一行代码,你敢说你正确?
从月份(5).开始().每一个(工人 => 工人.工资.增加(x => x * 0.1))
从程序员的角度来讲,肯定是不对的
应该是 从2010年5月1号开始,对每一个入职时间在2010年4月30号23点59分59秒起的未辞职的员工的工资按其在2010年4月所发工资基数增加百分之一,如果此员工2010年4月没有工资,按其级别默认工资处理,如果此员工未转正按80%计算,如果此员工被处罚。。懂了吗?为什么我们写个软件这么痛苦
修改一下楼主的代码 希望不要介意!
namespace 单例模式
{
public partial class frmChildren : Form
{
private frmChildren()
{
InitializeComponent();
} //声明一个静态的自己类型的变量
private static frmChildren _objFrmChildren = null; //构造方法改为私有,使外部代码无法通过 new 来实例化
private void frmChildren_Load(object sender, EventArgs e)
{ } static object obj = new object();//用于保持同步的对象 //外部代码通过这个方法来获取 类 的实例 以代替类构造函数功能
public static frmChildren GetInstance()
{
//判断实例是否存在,不存在则调用构造方法
if (_objFrmChildren == null || _objFrmChildren.IsDisposed)
{
lock(obj)
{
if (_objFrmChildren == null || _objFrmChildren.IsDisposed)
{ _objFrmChildren = new frmChildren();
_objFrmChildren.MdiParent = frmMdiParent.ActiveForm;
}
}
}
return _objFrmChildren;
}
}
}
我相信每一个刚刚接触到DSL的人都觉得这太不可思议,这对程序员传统的思维冲击太大了。为了说明这个问题,你需要的准备知识太多太多。打一个不恰当的比方,如同你给一个200年前的人讲汽车为什么能跑,在他不理解汽油机工作原理的情况下,他很难想象出来。他的提问可能是请你回答牲口拴在哪里,是在前面拉还是在后面推,这些都没有怎么行这样的问题。当然这个比喻非常不恰当。
你要理解,传统的编程模型中,数据是在命令的作用下流动。而在领域语言里面,程序是在运行期间被凭空造出来的,而创造程序的不是程序员,而是业务引擎。
第二个问题我不知道你说的是什么
关于性能,恰恰当前的编程模型出现了问题。现在业界的观点是,可伸缩性比单纯的性能更重要。如果程序具有良好的伸缩性,提高性能的办法就是购买足够多的硬件。你知道硬件比人工成本低很多。Ruby最大的诟病就是性能,恰恰像twitter这种数亿人访问的网站却架构于此。对于性能的另一种看法是,要用发展的眼光来看。在VMWare诞生的年代,没有人看好在一台计算机里面再运行一台虚拟机的模式,可是现在虚拟化已经深入人心。我能做的很有限,可能没有办法给你满意的答复。可能我的文章更多的是给技术决策者和对DSL已经有些研究正在打算付诸行动的人提供一点参考的。
真正不要改代码,用户用了还说好的,有吗?
DSL解决的不是写出一个不用改,到处能用的软件。如同汽车不是用来解决马不吃草也能跑的问题的。
我想回答你这些问题并不重要。
DSL解决的是用更贴近业务而不是面向实现的方式来编程。
DSL并不能预见到业务的变化,更不是一个实现了所有业务的代码库。如果大家有兴趣,应该去系统的学习。
主要是你那些 加上、扣除、以及运算符什么的,让我看不明白,
建议你用最简单的语法来实现,如果追求花哨的语法,反而掩盖了设计模式的真正意图。比如用简单的语法来实现:class SalaryItem{
string ItemName = "";
EnumDrCr DrCr = EnumDrCr.Dr; //Dr是收入,Cr是支出
DataType ItemType = DataType.Money; //有时需要录入字符,比如备注、违规记录,用于打印工资表
int ShowOrder = 0; //排列顺序,列表显示和打印时有用
bool isValid = true; //是否启用,对于一些工资项目,有段时间有用,有段时间又用不到。
bool isPrint = true; //是否打印,打印工资表时有用
bool isTax = true; //是否扣税,一些项目不能扣个人所得税,每个企业的工资都有扣个人所得税,
string formula = ""; //计算公式,这里为什么不用方法,因为公式由客户指定,所以不能使用方法.
//但是公式的解析,需要用到c#一些偏门的技术
int ExecOrder = 0; //公式执行顺序,因为项目有横向关联,公式可能引用
//别的项目,所以被引用的,必须比调用者先执行。
bool AllowEdit = false;//对于有公式的项目,是否允许编辑,
//比如扣押金是一个公式,但是计算出来的结果,
//用户还可能更改,比如系统算出来是300,
//但用户觉得扣的太多,只扣200,由100给员工吃饭。
}
http://www.searchsoa.com.cn/showcontent_28544.htm
http://tech.it168.com/o/2007-09-07/200709071212798_1.shtml
http://www.searchsoa.com.cn/showcontent_28544.htm请问有没有其它资料介绍介绍?
其实根本不需要,逻辑是你在SQL写的,SQL解释器动态执行这些代码。如果你不了解SQL,这些问题怎么回答呢?
本来我想把公式和项目放到一起,
但看来还是得分开,以前设计时也是分开的,
我把他放到一起是为了省代码,
现在看来还得分开,那工资项目的属性就减少了:
//工资项目类
class SalaryItem{
string ItemName = "";
EnumDrCr DrCr = EnumDrCr.Dr; //Dr是收入,Cr是支出
DataType ItemType = DataType.Money; //有时需要录入字符,比如备注、违规记录,用于打印工资表
int ShowOrder = 0; //排列顺序,列表显示和打印时有用
bool isValid = true; //是否启用,对于一些工资项目,有段时间有用,有段时间又用不到。
bool isPrint = true; //是否打印,打印工资表时有用
bool isTax = true; //是否扣税,一些项目不能扣个人所得税,每个企业的工资都有扣个人所得税,
}
然后再建立 工资方案 类,就是前面说的 普通职工 一套方案,高级职工一套方案那种:
class SalaryScheme{
string SchemeName = "";
int year = 0; //年
int month = 0; //月
}//方案项目类
class SalarySchemeItem{
string SchemeName = "";
string ItemName = "";
string formula = ""; //计算公式,这里为什么不用方法,因为公式由客户指定,所以不能使用方法.
//但是公式的解析,需要用到c#一些偏门的技术
int ExecOrder = 0; //公式执行顺序,因为项目有横向关联,公式可能引用
//别的项目,所以被引用的,必须比调用者先执行。
bool AllowEdit = false;//对于有公式的项目,是否允许编辑,
//比如扣押金是一个公式,但是计算出来的结果,
//用户还可能更改,比如系统算出来是300,
//但用户觉得扣的太多,只扣200,由100给员工吃饭。
}方案是每个月一套方案,可以从以前月份复制方案
加上("出勤奖", 300).
加上("清凉补贴", 200).
参照("基本工资").加上("浮动奖励 10%", x => x * 0.1).
在总数的基础上加上("董事长奖金 15%", x => x * 0.15).
加上("新年/平时补贴", () =>
{
if (DateTime.Now.Month == 1)
return 1000;
else
return 500;
}).
参照("基本工资", "浮动奖励 10%").扣除("押金 (基本工资和浮动奖励的5%)", (x, y) => (x + y) * 0.05).
扣除("水电扣除", 100);
给一个完全不懂编程的人看,他马上告诉我,这不就是给这个工资加上这个、这个、这个项么。但是程序员不同,他会问
参照() 这个函数返回什么?它为什么就会参照后面那个方法中给出的表达式?
在总数的基础上加上("董事长奖金 15%", x => x * 0.15),把表达式写在这里是什么类型?
他们总是用自己已有的编程经验去思考。
结果客户说还有B功能,你又做B功能给他,
结果客户又说还有C功能,你又做C功能,结果发现C与A有冲突,
于是为了加C功能,又要去改A功能,于是你就对客户发火了,
开始不是这样说的吗,怎么又要这么说,
客户也对你发火,明明是你不懂,怎么说我没说清楚呢?
你都没搞懂就去写程序了,难道怪我吗?
结果最后肯定是客户说了算,
结果越加越多,代码越加越乱,最后,自己只想一觉睡下去就永远不起来了。
不起来了,客户还要拉你起来鞭尸,人家的软件正在使用,一大堆问题等你解决,
你怎么能一走了之,这就是真实情况,并非杜撰。
什么DSL,什么设计模式,什么对象,能解决问题才是好东西,
不要抓住个什么 DSL 就当救命稻草,
你真正做时才会知道稻草是救不了你的命的。我说过,争论应该围绕解决实际问题 这个中心来展开,
但你说的,并不是围绕 解决实际问题来展开,而是围绕 DSL 展开。
DSL 能给你发工资么?
解决客户的问题,客户才会给钱给你,DSL不能给钱给你。明白不。你自己说的:112楼
http://topic.csdn.net/u/20110419/17/64e426e2-e447-4bfa-99c8-a8c71fdb0a66_2.html
说实在,我一想这东西你说的很对,没办法扩展的。写写简单的还将就,一复杂我就不会了。
能坚持做的人就相当不错了,你比lz好得多,lz就直接回避这些变化。
而人的习惯语言是一种模糊性语言,很多情况下,客户的业务规则是会自我矛盾的从思维角度而言,大部分人善于描述事情,而不善于总结归纳规则;而计算机基本职能按规则办事(批量性事务)所以RUBY 的出现是一个好事情,他从另一个层面告诉我们,软件是可以这样做的
但RUBY要想成为一个通用性的语言,道路还很久远
因为DSL已经用实际行动告诉我们,在某些情况下,它是很好的因为还感兴趣的同学可以去进一步找找资料了
比如
http://zh.wikipedia.org/wiki/Ruby不感兴趣的同学也别担心,在计算机基本原理没改变前,计算机还是需要我们这些指令流翻译专家的
我非常地感兴趣我觉得DSL 至少可以帮我处理一些 自动JOB 的事务
兄弟别着急,就我的理解而言,可能DSL 更适合处理
横向变化、纵向变化、
横向关联、纵向关联
这种事情
所以对于DSL而言,他可以很直观地去描述 业务上的
横向变化、纵向变化、
横向关联、纵向关联而相反,HTML 更适合描述页面,SQL 更适合描述数据、C++\C#\JAVA则比较全能
就象一个武林高手,他手中的兵器,仅仅是个工具而已,
他个人的武功修为,才是根本。当然,现在各种热武器横行,枪炮横行,
有人就认为 武功修为都没用了,武器才是最重要的。其实,武器越厉害,杀伤性越大,对个人的修为要求越高。因为,对别人危害越大,那对自己的危害也越大。各种计算机工具、技术,也是同样的道理,慢慢领会吧。
你有没有想过,为什么我们的系统不能重构?因为充斥了大量垃圾代码、无效的逻辑、荒废的判断如果真的有DSL这样简洁、直观的工具,而且不断坚持系统级别的重构,系统才能保持活力别再争论了,DSL是一个事实
哈哈。
但是浪费的资源,迟早会还的,不要以为那么简单。