论坛首页 Java企业应用论坛

再次小结领域模型的种种观点

浏览 146225 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-01-02  
ajoo 写道
firebody 写道
^_^,再仔细想了一下,决定利用这几天空闲的时间作出一个beta的RuleEngine来,现在有点兴奋,感觉这是一个非常的思路,前期的工作可能大一些,但是对于需要灵活定制、修改策略的需求来说,这样的一个基于Script的Rule Engine还是很有必要的,各位,可否告诉我已经有人做了这样类似的咚咚,如果没有人,^_^,我要开始干活了,把它放到SF上去。

drools之类的不是就做这个活的么?

我的rule ToolKit的目的和它的不同。
在作Rule Engine之前,我需要做一个类似Hashkell或者Lamba之类的函数解析器,虽然有点转牛角尖的感觉,不过感觉作起来挺有意思的,让组合子能够互相组合,互相运算,感觉有点排骨开天地的感觉,组合好了,就随便定义函数,然后解析运行,你可以就着你的想象定义函数,然后让函数按照数学含义来运行。
作着感觉劳动量有点大,不过已经开了头了,不想一下子就气馁,至少这个元旦我还是想用它来尝试一下的,目前已经进展到可以这样定义函数和运行得出结果:
script:

define function sum(x,y); as{ x+y*2+1+4/2};
define function anoSum(x); as{ x*sum(x,x+1); );;


appCode:
//retrieve parsed function
Func func = engine.parse(scirptPath);.getFunction("anoSum");;
//input the param

Object result = func.addArgument(1);.getResult(engine);;

assertEquals(new Double(8);,result);;



也可以实现递归函数:
define function F(x);  as{ 
if(x==0);{1} 
else{x*F(x-1); }

 }


相当于这么一个数学定义:
         
F(x); =  {x==0: 1} or { x*F(x-1);}


如果这个函数解析器完善了,我想我可以以它为基础作很多基于项目的应用了,比如典型的Rule engine 。
因为要考虑到可扩展性,我里面的设计基本按照前面我提出那几个原则来设计,比较主要的是用户可以定制或者重载操作符号,函数参数的翻译接口,已经简单方面的Function接口,可以让用户自己定义函数:
比如用户可能需要这么一个元数据类型的规则,判断当前日期是否位于某个期限内:

isInDiscountTime('2005/11/11','2006/1/12') ,假设用户可以定义这么一个函数,那么我需要用户可以自己负责解析参数。

利用函数解析器,用户可以在其中架起script 和 java code之间的侨联,利用java写一些复杂的函数,拥有意义的参数,那么通过脚本传入不同的参数,就可以实现更灵活的定制了。

函数的组合也很关键,比如可以这样:
define func1(x,y); as {..}

define func1(x); as {...}

define func3(x,y); as {...}
define func(); as{  
 func3(func1(1,2);,func2(3); );+2+3 }
0 请登录后投票
   发表时间:2006-01-03  
偶的jaskell就是这样的东西呀。呵呵。

设计语言之前,你得先想好几点:
1。dynamic scope vs. static scope
2。call-by-value, call-by-need or call-by-name?
3。支持currying么?
4。强类型?动态类型?
5。语言有没有java规范内的动态语义?比如你在script里面写个1,它输出到java里是Integer? Long? BigInteger?
6。支持什么样的数据结构?list?hashtable?string?regular expression?tuple?
7。支持pattern match么?
8。支持monad的do-notation么?(这个很重要,否则在组合高阶逻辑方面用lamda函数还是比较难看。)

暂时先想到这么多。

另外,你这个不是函数组合呀。如果用call-by-value语义,你组合的是函数返回值,而不是函数。
高阶组合可以比这个复杂多了的。比如:

do
  v1<- rule1
  v2 <- rule2
  return (v1>v2);
0 请登录后投票
   发表时间:2006-01-03  
ajoo 写道
偶的jaskell就是这样的东西呀。呵呵。

设计语言之前,你得先想好几点:
1。dynamic scope vs. static scope
2。call-by-value, call-by-need or call-by-name?
3。支持currying么?
4。强类型?动态类型?
5。语言有没有java规范内的动态语义?比如你在script里面写个1,它输出到java里是Integer? Long? BigInteger?
6。支持什么样的数据结构?list?hashtable?string?regular expression?tuple?
7。支持pattern match么?
8。支持monad的do-notation么?(这个很重要,否则在组合高阶逻辑方面用lamda函数还是比较难看。)

暂时先想到这么多。

另外,你这个不是函数组合呀。如果用call-by-value语义,你组合的是函数返回值,而不是函数。
高阶组合可以比这个复杂多了的。比如:

do
  v1<- rule1
  v2 <- rule2
  return (v1>v2);

可以这样理解吗?
v1 = rule1;
v2 = rule2;
return (v1>v2);

Haskell中的<-操作符其实就是相当于定义一个局部变量,保存右边表达式返回的值。
我现在已经全部实现了我所能想到的,现在我正在看Haskell,对里面灵活而又富有意义的组合操作符很感兴趣,另外从Hashkell我可以感觉到,用计算机语言对函数的运算,目前只能做到:

1) 可递归的运算模型,如果要做一个比较复杂的操作,那么这个可递归的运算模型需要比较精巧的设计(在函数式语言中,可以通过组合来避免java/c++ 冗长的代码 )

2) 有限维的发散计算。 比如对于一个序列1....n,只要求真对某个函数计算到特定长度的值。

至于你说的
4。强类型?动态类型?
5。语言有没有java规范内的动态语义?比如你在script里面写个1,它输出到java里是Integer? Long? BigInteger?


这里感觉还是比较复杂的,Haskell用可定义输入,输出类型。
这是几个可行的思路:
1)一种做法就是让用户自己解析,我只给他一个字符串,它负责解析函数体和参数里面的所有字符。

2)针对集中常用类型,让用户定制特定的解析器,比如数字,日期。数字用户可能需要BigDecimal . 另外,+.-.*./,如果涉及到精确的计算,用户可以自己重载这些基本操作符。

常用的数据结构:
6。支持什么样的数据结构?list?hashtable?string?regular expression?tuple?

我想这些可以定制,比如一个list,可以这样做:

define list as {class:jfun.fp.listFunc};
define tail as{class:jfun.fp.tailList};
define head as {class:jfrun.fp.HeadList};

list的组合操作符: ++,:都可以通过定义操作符号来实现

用户可以这样写函数script:
define func1(); as{ tail(list(1,2,3,4););++list(5,6); };
将返回list ,(2,3,4,5,6);.
0 请登录后投票
   发表时间:2006-01-03  
引用
Haskell中的<-操作符其实就是相当于定义一个局部变量,保存右边表达式返回的值。

这个错的有点离谱了。"<-"和"="完全是两个不同的东西。怎能混为一谈?


右面表达式的值是一个高阶逻辑对象。而"<-"左边的符号代表的是这个高阶对象一旦运行所产生的结果。如果用"=",左边的符号才是这个表达式的值:那个高阶对象。

你对1和2的回答也好像答非所问。或者我的思维还不够发散?


我刚刚完成了用jaskell给我的这个rule combinator包装的外壳,结果程序如下:
final_discount where
  Calendar = jaskell.java.import "java.util.Calendar";
  isMonth m = eq(m, cre.datepart "MONTH");;
  isDay d = eq(d, cre.datepart "DAY_OF_MONTH");;
  purchase ctxt = ctxt.getPurchasedProducts[];
  purchased product = do {products=purchase} $
    products.contains[product];
  purchased_all products = cre.and(jaskell.prelude.map purchased products);;
  discount d = return (1-d);;
  cardtype ctxt = ctxt.getCardType[];
  gender ctxt = ctxt.getGender[];
  discountByMember type v = (eq type cardtype);.then (discount v);;
  gold_member = discountByMember "gold" 0.1;
  silver_member = discountByMember "silver" 0.05;
  platinum_member = discountByMember "platinum" 0.2;
  by_member = cre.any[platinum_member, gold_member, silver_member];
  is_female = eq "female" gender;
  is_female_day = cre.and[isMonth(Calendar.MARCH);, isDay 8];
  female_discount = discount 0.05 `when cre.and[is_female, is_female_day];
  tvspeaker = discount 0.05 `when purchased_all["tv", "speaker"];
  tvspeakerdvd = discount 0.07 `when purchased_all["tv", "speaker", "dvd"];
  by_purchase = cre.any[tvspeakerdvd, tvspeaker];
  final_discount = cre.fold (*); 1 [by_member, female_discount, by_purchase];
end


那个"do{product=purchased} $"对应的就是"do product<-purchased"。

测试通过。
0 请登录后投票
   发表时间:2006-01-03  
右面表达式的值是一个高阶逻辑对象。而"<-"左边的符号代表的是这个高阶对象一旦运行所产生的结果。如果用"=",左边的符号才是这个表达式的值:那个高阶对象。

那我所说的=就是指高阶对象运算产生的结果。  可能表达不大一致罢了 ,我理解的fp是没有引用赋值的概念的。
另外,看了你写的那个脚本,感觉很难看懂。 语法不是很亲切,其实Hashkell的思想很好,但是语法不好,我觉得不应该再使用那种晦涩难懂的语法。
另外,关于java的函数组合,apache已经作了很多尝试,其中有一个已经成形的库:org.apache.commons.functor.

里面主要作了闭包,函数组合的封装。 全部是对象的方式。
主要作了可以传递函数对象的形式,并提供特有的绑定支持。部分实现currying功能。
这些都可以用来组合实现复杂的业务规则。

,以前没看过FP的东东,基础很差阿。很多东西理解错了,大家别笑话阿。 赫赫
0 请登录后投票
   发表时间:2006-01-04  
firebody 写道
右面表达式的值是一个高阶逻辑对象。而"<-"左边的符号代表的是这个高阶对象一旦运行所产生的结果。如果用"=",左边的符号才是这个表达式的值:那个高阶对象。

那我所说的=就是指高阶对象运算产生的结果。  可能表达不大一致罢了 ,我理解的fp是没有引用赋值的概念的。
另外,看了你写的那个脚本,感觉很难看懂。 语法不是很亲切,其实Hashkell的思想很好,但是语法不好,我觉得不应该再使用那种晦涩难懂的语法。
另外,关于java的函数组合,apache已经作了很多尝试,其中有一个已经成形的库:org.apache.commons.functor.

里面主要作了闭包,函数组合的封装。 全部是对象的方式。
主要作了可以传递函数对象的形式,并提供特有的绑定支持。部分实现currying功能。
这些都可以用来组合实现复杂的业务规则。

,以前没看过FP的东东,基础很差阿。很多东西理解错了,大家别笑话阿。 赫赫


其实jaskell很类似lisp,相当地贫语法。多数东西都是函数啊函数。你所谓的“看不懂”大概还是一些函数怎么用没懂。即使haskell的语法我也不认为有什么晦涩的,比java简洁多了。你不喜欢主要还是先入为主罢了。习惯了不加括号的函数调用方式就好了。要说难懂,也是高阶函数组合比较难懂。




所涉及到的语法点:
[list]1。函数调用可以用f(a,b)的形势,也可以用f a b的形势。
2。反单引号"`"把函数用中缀语法调用。"a `when b"相当于 "when(a,b)"。
3。"$"用来改变优先级。"f $ a b"相当于"f(a(b))"。而没有"$"的话,"f a b"相当于"f(a,b)"。
4。"a.method"就是oo的语法,相当于对对象"a"调用"method"。它也用来从namespace中引用对象——因为namespace本身也是一个对象。
5。[a,b,c]是一个list。
6。{a=b}是一个tuple。类似于一个field a的值为b的object。[/list:u]

其它就都是函数了。"and", "or", "any", "when", "then", "eq","return"等等等等。


不过你能给出更好的语法也好啊。

上面的script和我前面给出的java测试代码是完全对应的。只不过加了一个script外壳。那个java程序是:
 
private Rule getRule();{
   final Rule gold_member = MyRules.discountByMember("gold", 0.1);;
    final Rule silver_member = MyRules.discountByMember("silver", 0.05);;
    final Rule platinum_member = MyRules.discountByMember("platinum", 0.2);;
    final Rule by_member = MyRules.any(new Rule[]{platinum_member,
        gold_member, silver_member});;
   
   
   
    final Rule is_female = MyRules.isGender("female");;
    final Rule is_female_day = MyRules.isMonth(Calendar.MARCH);
        .and(MyRules.isDay(8););;
    final Rule female_discount = is_female.and(is_female_day);
        .then(MyRules.discount(0.05););;
   
   
   
    final Rule tvspeaker = MyRules.purchased(new String[]{"tv","speaker"});
        .then(MyRules.discount(0.05););;
    final Rule tvspeakerdvd = MyRules.purchased(new String[]{"tv","speaker","dvd"});
        .then(MyRules.discount(0.07););;
    final Rule by_purchase = MyRules.any(new Rule[]{tvspeakerdvd, tvspeaker});;
   
    final Rule final_discount = MyRules.productDouble(new Rule[]{
      by_member, female_discount, by_purchase
    });;
    return final_discount;
  } 


apache的functor?只不过实现了一些最简单的组合, 个人认为实用价值真的没什么.
0 请登录后投票
   发表时间:2006-01-04  
发现搞这FP的咚咚,很容易有”走火入魔”的迹象。
赫赫,用它来做一些事情还是很有意思的。 不过的先放一段时间,这个元旦
差点走火入魔了。  
0 请登录后投票
   发表时间:2006-01-09  
现在想想,其实CO(FP?)关注的是更细小的单位(语句级别上逻辑的封装)上的重用,OO关注的是中等粒度的单位(方法和操作数据的封装)上的重用,他们是不能互相替代的吧?

Functor(CO/FP) &lt; Object(OO) &lt; Component(Midware) &lt; Service(SOA) ?

回到之前的问题,
pig345 写道
CO方式,能否用来做Domain的设计/实现?

或者,怎么摆脱分类的方式建模?
0 请登录后投票
   发表时间:2006-01-09  
这个理解和我的比较相似。

我也认为co适合在用OO把问题分解到一定的粒度后进行。不管需求的变化多复杂,问题域需要集中,高内聚。


不过OO我也不认为分类就是好方法。所谓“分类”的这个“分”字,更强调全局性地把问题分解成固定的几个子类。

面向接口编程更合适用角色驱动来描述。角色并不存在只此一家的宇宙唯一分类标准。它是面向各个单一模块的需求的,全局设计上到底分多少类我根本不关心,只要给这个模块的需求用接口描述出来即可。
0 请登录后投票
   发表时间:2006-02-22  
Readonly 写道
robbin 写道
好吧,那么我是web程序员,我从页面传一个id过来,要先load一下该Account,显示account的信息。那么请问:你提供给我什么API?是
account.getAccountById(id);
还是
accountService.getAccountById(id);
还是
accountDao.getAccountById(id);
?


new Account(id);


Account.get(id)
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics