软件艺术思考者  
混沌,彷徨,立志,蓄势...
公告
日历
<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

随笔分类(86)

随笔档案(85)

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 
现在后台分成如下几个层:
Domain:提供getter/setter
Dao:接口,定义了持久化方法,CRUD
DaoImpl:Dao的实现
Service:业务逻辑

但是在实际的过程中发现,service里面有很多涉及到持久化的查询、更新操作,那么,这些方法是在dao中定义呢?还是在service中定义和实现?
比如,对于一个 客户资料UserOrder 实体
dao中定义了getUserOrderByID() getAllUserOrder() insertUserOrder() updateUserOrder() delUserOrder()五个方法
现在需要一个 根据地区查询客户getUserByArea(),或者 根据产品线和地区查询客户 getUserByAreaSrv()
这样的方法,定义在service还是dao中?
第二个问题。service层肯定是面向客户端调用的,那么dao层对于客户端是否暴露?
就是说,service层中是否提供dao中的方法,比如getAllUserOrder() insertUserOrder()这些方法?
如果不提供,那么客户端需要知道哪些是dao中提供的,哪些是service提供的
如果提供这些方法,意味着所有的方法需要在dao中定义,daoimpl中实现,service中包装,是否太重复和烦琐?
1.
DAO只负责数据库操作,不涉及任何逻辑,Service就需要业务逻辑了,比如getUserOrder()在DAO,你就查数据库就行,在service中,你可能需要首先验证当前用户是否有这个操作权限,然后调用DAO,最后记录日志
2.需要在dao中定义,daoimpl中实现,service中包装,是否太重复和烦琐?
其实这不会发生,因为你认为getUserByAreaSrv()方法肯定一定要完全从数据库完成,其实不然,其实我可能只从数据库查询一个ID集合,然后,在服务层再通过缓存访问封装成完整的Model。这些都需要在Service完成(只是一个比喻)。

预留Service是为防止你的业务系统复杂化之后有一个插脚的地方。

现在很多系统就没有这种插脚的地方,在struts的Action中直接调用Hibernate数据库操作,如那个日本人做的开发框架RoR就是这样,这些以丧失可维护性做代价的快速开发都是伪框架。

所以,为你的系统将来留着Service
3.我认为Dao层还是不要暴露在最外层为妙,即Service以外的层次都无法调用。否则实体化与应用逻辑以及界面之间的耦合度将无法控制,导致产品的生命周期缩短,可扩展性遭到破坏。
Service层当然也可以有getUserOrderByID() 这样的操作,但最好通过调用DAO来实现,或者像banq说的以dao-cache的方式来实现,而不是直接去做实体操作。这样做可能会感掉有些重复繁琐,但会给产品今后的升级补充带来好处。可能会多出这30%的代码量,但带来的好处是起码能延长代码30%的生命。
Service的方法定义和方法内的参数定义更倾于业务逻辑,而不是存储方式。而Dao的定义则跟存储方式直接挂钩,而不需要过度考虑业务逻辑。所以代码上的“繁琐”恰恰代表了逻辑上的“简单”。
更重要的是Service是必须的。
22一般service层是怎么实现的?是不是就是一个拥有很多静态方法的类,每个静态方法处理一些业务逻辑,还是有什么其它的方法,望指教
1我还有疑问,比如CoreFeeService好像是操作CoreFee这个domain bean的,如果我有一段业务逻辑,是调用CoreFeeService改变CoreFee的一些属性,然后将CoreFee持久化到数据库,接着可能要调用另一个domain bean的service方法。

在Struts框架中,这段代码是写在Action中,还是别的地方,Action又好像应该只控制转发,不应该有业务的代码在里面。但像上面那样,可能还有事务处理,这时我该怎么做好呢?
2你描述的这段设计本来就是包含了业务逻辑。当然应该在Service里。service本身包含了粒度不同的操作,粗粒度的操作(方法)里可以包含很多细粒度的操作。这些细粒度的操作可以是private,也可是是public(如果别的action需要它)。
Action的概念当然跟业务本身是有一定关系的。你可以在action的代码中表示出一些业务上的逻辑关系,但要节约。能在service中实现的最好在service中。这对程序结构是有好处的。
你说:“Action又好像应该只控制转发,不应该有业务的代码在里面”——这句话体现出你可能已经成为“框架”的“受害者”了。要用“框架”来提炼你的设计,而不要用来约束你的思维。不要指望从“框架”中找到理清软件开发一切思路的“银弹”——因为它根本不存在。
posted on 2006-07-24 16:02 智者无疆 阅读(1710) 评论(5)  编辑  收藏 所属分类: software project
评论:
  • # re: 关于软件分层的讨论  白白 Posted @ 2006-07-24 17:43
    支持支持!!
    http://hi.baidu.com/luzhu33  回复  更多评论   

  • # re: 关于接口  智者无疆 Posted @ 2006-07-25 10:56
    关于接口, 我再来废话几句:
    有时候, 一个东西可以“ 是” 几个东西。不明白这句话吗? 我就拿我自己来举个例子吧:
    我“ 是”一个程序员、一个老师、一个作者、一个父亲… … 你可以说我“ 实现了老师的接口”,
    学生们会向我询问关于上课的问题。我还“ 实现了父亲的接口”, 但是我的学生可能知道这
    一点, 也可能不知道。如果他们知道这一点, 他们就可以放心的向我询问关于抚养小孩的问
    题了。
    但是, 尽管我实现了所有这些接口, 我还有一个抽象类— — “ 人”。这个抽象类给我提
    供了所有的默认行为( 比如说我偶尔会走背运)。  回复  更多评论   

  • # re: 关于接口  智者无疆 Posted @ 2006-07-25 10:59
    面向接口编程
    面向接口编程
    在前面的章节中,我们提到一个接口设计的例子。为什么我们提倡接口的设计呢?Martin Fowler在他的分析模式一书中指出,分析问题应该站在概念的层次上,而不是站在实现的层次上。什么叫做概念的层次呢?简单的说就是分析对象该做什么,而不是分析对象怎么做。前者属于分析的阶段,后者属于设计甚至是实现的阶段。在需求工程中有一种称为CRC卡片的玩艺儿,是用来分析类的职责和关系的,其实那种方法就是从概念层次上进行面向对象设计。因此,如果要从概念层次上进行分析,这就要求你从领域专家的角度来看待程序是如何表示现实世界中的概念的。下面的这句话有些拗口,从实现的角度上来说,概念层次对应于合同,合同的实现形式包括接口和基类。简单的说吧,在概念层次上进行分析就是设计出接口(或是基类),而不用关心具体的接口实现(实现推迟到子类再实现)。结合上面的论述,我们也可以这样推断,接口应该是要符合现实世界的观念的。

    在Martin Fowler的另一篇著作中提到了这样一个例子,非常好的解释了接口编程的思路:


    interface Person {
    public String name();
    public void name(String newName);
    public Money salary ();
    public void salary (Money newSalary);
    public Money payAmount ();
    public void makeManager ();
    }
    interface Engineer extends Person{
    public void numberOfPatents (int value);
    public int numberOfPatents ();
    }
    interface Salesman extends Person{
    public void numberOfSales (int numberOfSales);
    public int numberOfSales ();
    }
    interface Manager extends Person{
    public void budget (Money value);
    public Money budget ();
    }



    可以看到,为了表示现实世界中人(这里其实指的是员工的概念)、工程师、销售员、经理的概念,代码根据人的自然观点设计了继承层次结构,并很好的实现了重用。而且,我们可以认定该接口是相对稳定的。我们再来看看实现部分:


    public class PersonImpFlag implements Person, Salesman, Engineer,Manager{
    // Implementing Salesman
    public static Salesman newSalesman (String name){
    PersonImpFlag result;
    result = new PersonImpFlag (name);
    result.makeSalesman();
    return result;
    };
    public void makeSalesman () {
    _jobTitle = 1;
    };
    public boolean isSalesman () {
    return _jobTitle == 1;
    };
    public void numberOfSales (int value){
    requireIsSalesman () ;
    _numberOfSales = value;
    };
    public int numberOfSales () {
    requireIsSalesman ();
    return _numberOfSales;
    };
    private void requireIsSalesman () {
    if (! isSalesman()) throw new PreconditionViolation ("Not a Salesman") ;
    };
    private int _numberOfSales;
    private int _jobTitle;
    }



    这是其中一种被称为内部标示(Internal Flag)的实现方法。这里我们只是举出一个例子,实际上我们还有非常多的解决方法,但我们并不关心。因为只要接口足够稳定,内部实现发生再大的变化都是允许的。如果对实现的方式感兴趣,可以参考Matrin Fowler的角色建模的文章或是我在阅读这篇文章的一篇笔记。

    通过上面的例子,我们可以了解到,接口和实现分离的最大好处就是能够在客户端未知的情况下修改实现代码。这个特性对于分层技术是非常适用的。一种是用在层和层之间的调用。层和层之间是最忌讳耦合度过高或是改变过于频繁的。设计优秀的接口能够解决这个问题。另一种是用在那些不稳定的部分上。如果某些需求的变化性很大,那么定义接口也是一种解决之道。举个不恰当的例子,设计良好的接口就像是我们日常使用的万用插座一样,不论插头如何变化,都可以使用。

    最后强调一点,良好的接口定义一定是来自于需求的,它绝对不是程序员绞尽脑汁想出来的。

      回复  更多评论   

  • # re: 关于接口  智者无疆 Posted @ 2006-07-25 11:09
    到今天,我彻底的明白了为什么有些服务层对象要用接口来声明了。这是因为当我们在action里面用接口来声明业务对象以后,不管你以后怎么修改业务对象的实现类都可以,甚至包括更改类名(实现类)都不用修改action里的代码。  回复  更多评论   

  • # re: 关于软件分层的讨论  王胜利 Posted @ 2006-07-25 17:46
    顶  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
 
Copyright © 智者无疆 Powered by: 博客园 模板提供:沪江博客


   观音菩萨赞