`

一个简单的菜单管理,我却迷茫了,求解惑

阅读更多
一、需求
    做一个简单的CMS,关于菜单部分的需求。
    系统管理员输入账号密码登陆后台系统后,首页面显示布局为:顶部水平显示一行导航菜单,左边栏显示树形菜单,点击不同的导航菜单,左边栏显示不同的树形菜单。中间是工作区。
    系统管理员在导航菜单中点击菜单管理,左边栏显示:
   
    导航菜单
       |——所有导航菜单
       |——添加导航菜单
    树形菜单
       |——所有树形菜单
       |——添加树形菜单

    点击添加树形菜单,工作区弹出添加页面,从上到下要求包括:
   
    所属导航菜单(点击下拉列表,必填)
    父菜单(点击下来列表,可以不选表示没有父菜单)
    菜单名(必填,必须中文,2-8字,不能与现有树形菜单同名)
    url(必填)
    排序(整数型,必填)

    提交后,要验证导航菜单和父菜单是否存在。
    其他更详细的描述略之。

二、需求分析(场景在前面有描述,下面有所省略,主要围绕添加树形菜单)
    1.业务建模
        (a)业务用例:管理菜单
    2.用例分析
        用例:管理菜单
        业务活动:添加树形菜单,修改树形菜单,删除树形菜单,查询所有树形菜单,查询所有导航菜单,根据菜单名查询导航菜单,根据菜单名查询树形菜单
    3.系统建模
         用例:把上者的业务活动的节点作为一个系统用例
         用例关系:菜单管理include(添加树形菜单include(查询所有导航菜单,查询所有树形菜单,根据名字查询导航菜单,根据名字查询树形菜单))
         系统架构:B/S,REST,MVC...
         系统范围:...
         ...

三、概要设计
    1.领域模型:导航菜单,树形菜单
    2.包+类:
          menu
           |—controller
           |     |—TreeMenuController.class
           |—service
           |     |—MenuManager.class
           |—dao
           |   |—TreeMenuDAO.class
           |   |—NavMenuDAO.class
           |—entity
                |—TreeMenu.class
                |—NavMenu.class

     PS:1.原谅我用贫血模型 2.po和dto几乎一样,用entity算了
                

    3.领域类:NavMenu,TreeMenu
    4.领域类关系:NavMenu(1) —关联— (n)TreeMenu 树形菜单中 父菜单(1) —父子— (n)子菜单
    5.类图:...
    ...

四、困惑
    说困惑之前说说我的想法。
    1.因为TreeMenu需要依赖NavMenu,所以模块划分的时候,抽象一个层次为Menu
    2.同样考虑,抽象为MenuManager来做服务接口。
    3.MenuManager依赖DAO接口,不依赖具体实现,具体实现类通过外部框架进行注入,从代码层面上解耦。
    困惑来了。
    1.采取的是贫血模型,如果我要用充血模型,请问怎么做?我尝试过,可是感觉失败了。我自己的做法是:
    menu
     |—application
     |       |—TreeMenuController.class
     |       |—TreeMenuVO
     |       |—NavMenuVO
     |       |—NavMenuService.class
     |       |—TreeMenuService.class
     |       |—impl
     |            |—TreeMenuServiceImpl.class
     |            |—NavMenuServiceImpl.class
     |—domain
     |     |—NavMenu.class
     |     |—NavMenuRepository.class
     |     |—TreeMenu.class
     |     |—TreeMenuRepository.class
     |—infrastructure
              |—NavMenuDAO.class
              |—TreeMenuDAO.class
              |—NavMenuPO.class
              |—TreeMenuPO.class
              |—TreeMenuAssembler.class
              |—NavMenuAssembler.class
              |—impl
                  |—NavMenuDAOImpl.class
                  |—TreeMenuDAOImpl.class

    几点说明:TreeMenuVO、NavMenuVO是DTO,TreeMenuPO、NavMenuPO是持久化对象,他们都由TreeMenuAssembler和NavMenuAssembler负责组装,po数据从数据库查出来,然后将数据装配到domain里,最后继续装配到vo里。反之亦然。

    依赖关系:controller——>service——>repository——>dao

    这么下来后感觉怪怪的,多了好多类,不知道这样算不算DDD。算不算领域模型驱动。囧。望朋友能够指正。
   
    2.对于TreeMenuService来说,它有个操作,添加树形菜单,需要去查询获取所有的导航菜单,那么这个查询操作属于NavMenuService的职责吗?当然,它一定属于NavMenuDomainObject的。假设它也属于NavMenuService的方法,那么我想问,TreeMenuServie可以调用NavMenuService的方法吗?或者我是否改抽象出一个MenuService来?

    补充:service主要作为事务边界和代理domain面向用户的接口,在其内部非简单代理domain的逻辑方法里,负责对多个domain的操作逻辑。而domain内部也有逻辑,但是这种逻辑仅与当前所在domain实例有关,不能与多个domain有关,如果是多个有关的话,应该要封装在service中。
    系统的dao,service都要面向接口编程,由外部框架进行依赖的注入。
    系统应该是按模块来进行包的组织。模块之间不能有任何的依赖,只能依赖公共组件。任何模块单独拿出来都能独立运行。
    前面说的menu就是一个模块。


分享到:
评论
2 楼 laiweiweihi 2011-10-10  
ltian 写道
看了一下,胡说几句。

1.这个充血模型应是领域模型驱动,虽然多了很多类,但是层次分清了,好处在于将来任意一层发生变化时,重构代码量比较小,业务逻辑清晰,出现问题容易定位和调整。在简单业务逻辑下可能会略显啰嗦,但是一旦业务逻辑复杂之后,便会体现其巨大优势(在于积累领域业务知识和可复用代码资产,更易于阅读和维护,将数据库操作隔离在特定层中等等好处)。

2.查询获取所有的导航菜单,那么这个查询操作属于NavMenuService的职责吗?当然,它一定属于NavMenuDomainObject的。这个我有异议:

NavMenu是聚合了其他类的根类,因此对业务逻辑类进行包括查询在内的管理职责一般交给Repository(负责访问数据,装配和发装配PO与BO),业务逻辑类本身不负责这个工作。聚合的根类可以根据业务逻辑关系查找其所聚合的其他类,比如查找TreeMenu。聚合的根类查找其所聚合的其他类也可以通过其他类的Repository类来进行,一般来说Repository类不对展现层暴露。


因此,还缺了一个工厂类,用于提供根据类型查找Repository类的工厂。通过这个工厂的接口,业务逻辑类可以在任何需要的代码中找到其所聚合或使用的其他业务类。

NavMenuService是对domain 及以下层次的封装。主要对展现层,或者其他外部模块提供访问的服务。他可能是对domain (BO)或者Repository类,所提供的功能进行简单逻辑组合或代理。细节性的业务逻辑应不在此类中实现,该类可以作为主框架程序。

3.整体命名未彰显层次概念,命名有待优化。从命名上看未能很好体现规划明确类层次,展现层、业务逻辑层、Repository、持久化层命名不够清晰。

4.从业务模型上看,NavMenu 和TreeMenu都是一个东西,应该可以抽象为一个叫Menue的类,而不是两个类。这会大量减少类及代码量。

哈,大哥哥一出手果然不凡,多谢如此认真的回帖。真心感谢。
1 楼 ltian 2011-10-10  
看了一下,胡说几句。

1.这个充血模型应是领域模型驱动,虽然多了很多类,但是层次分清了,好处在于将来任意一层发生变化时,重构代码量比较小,业务逻辑清晰,出现问题容易定位和调整。在简单业务逻辑下可能会略显啰嗦,但是一旦业务逻辑复杂之后,便会体现其巨大优势(在于积累领域业务知识和可复用代码资产,更易于阅读和维护,将数据库操作隔离在特定层中等等好处)。

2.查询获取所有的导航菜单,那么这个查询操作属于NavMenuService的职责吗?当然,它一定属于NavMenuDomainObject的。这个我有异议:

NavMenu是聚合了其他类的根类,因此对业务逻辑类进行包括查询在内的管理职责一般交给Repository(负责访问数据,装配和发装配PO与BO),业务逻辑类本身不负责这个工作。聚合的根类可以根据业务逻辑关系查找其所聚合的其他类,比如查找TreeMenu。聚合的根类查找其所聚合的其他类也可以通过其他类的Repository类来进行,一般来说Repository类不对展现层暴露。


因此,还缺了一个工厂类,用于提供根据类型查找Repository类的工厂。通过这个工厂的接口,业务逻辑类可以在任何需要的代码中找到其所聚合或使用的其他业务类。

NavMenuService是对domain 及以下层次的封装。主要对展现层,或者其他外部模块提供访问的服务。他可能是对domain (BO)或者Repository类,所提供的功能进行简单逻辑组合或代理。细节性的业务逻辑应不在此类中实现,该类可以作为主框架程序。

3.整体命名未彰显层次概念,命名有待优化。从命名上看未能很好体现规划明确类层次,展现层、业务逻辑层、Repository、持久化层命名不够清晰。

4.从业务模型上看,NavMenu 和TreeMenu都是一个东西,应该可以抽象为一个叫Menue的类,而不是两个类。这会大量减少类及代码量。

相关推荐

    java 解惑 java 解惑 java 解惑

    java 解惑 java 解惑 java 解惑 java 解惑 java 解惑 java 解惑

    SQL解惑解惑

    视图则是虚拟表,基于一个或多个表的查询结果,提供了一种抽象数据的方式,可以简化复杂的查询逻辑。 另外,事务处理是确保数据一致性的重要概念。SQL支持ACID(原子性、一致性、隔离性和持久性)特性,这意味着...

    IT学生解惑真经 IT学生解惑真经

    《IT学生解惑真经》是一本专门为在IT领域学习和探索的学生们量身打造的知识宝典。这本书的目的是帮助那些在信息技术世界中迷失方向、渴望深入理解和掌握核心技术的学子们,提供一套全面且实用的学习指南。书中的内容...

    《找事:给年青一代的就业解惑书》读书笔记.pdf

    * 三个故事:内卷、躺平和扑腾,焦虑是一个报警器 * “好工作”神话:过去的经验,还是留给过去吧,经济换挡,好工作更少了 第二章 你需要找事做,而不是找工作 * 工作是什么:传统的工作伦理骗了你,消费主义继续...

    Java解惑(中文版)_java_java解惑_solve65p_

    《Java解惑(中文版)》是一本专为Java初学者设计的学习资料,旨在帮助读者解答在学习Java过程中遇到的各种困惑。"solve65p"可能代表这本书包含65个问题或主题,每个都深入浅出地进行了讲解,旨在解决初学者在编程...

    C语言解惑中文版.pdf

    - **指针概念**:指针是一个特殊的变量,它存储的是另一个变量的内存地址。 - **指针操作**:包括指针声明、解引用(`*`)、取地址(`&`)等。例如: ```c int value = 10; int *ptr = &value; // ptr指向value的地址...

    SQL解惑(中文版)

    例如,可以通过构建一个简单的在线书店系统,实现用户登录、书籍查询、购物车管理等功能,来练习如何设计数据库结构、编写SQL查询、处理事务以及优化性能等。 ### 总结 《SQL解惑(中文版)》旨在帮助已经具备一定...

    java解惑 PDF版

    例如,判断一个整数是否为奇数时,使用`return i % 2 == 1;`可能看似正确,但实际上对于负奇数来说,这会导致错误的结果。正确的判断奇数的方法应该是`return i % 2 != 0;`。 取余操作符的使用需要注意其结果的符号...

    SQL解惑 第二版(中文)pdf带目录

    《SQL解惑 第二版(中文)》是一本专门针对SQL语言疑难点进行解析的书籍,旨在帮助读者在实践中理解和掌握SQL的各种特性和技巧。这本书以其独特的案例解析方式,为学习SQL的人提供了一种生动、易懂的学习路径,避免...

    linux一句话解惑

    linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑linux一句话解惑

    Java解惑 中文版

    《Java解惑中文版》是一本专为Java程序员设计的指南,旨在帮助读者解决在编程过程中遇到的各种问题,提升程序的健壮性。本书深入浅出地探讨了Java语言的核心概念、常见疑惑以及最佳实践,旨在使开发者能够编写出更...

    IT学生解惑真经PDF

    《IT学生解惑真经》是一本专门为在校计算机专业学生量身打造的指南书籍,旨在帮助学生在学习过程中解决疑惑,提供明确的学习路径和实践建议。这本书深入浅出地讲解了IT领域的基础知识,同时涵盖了现代信息技术的发展...

    sql解惑.pdf

    不过,我可以从标题和描述中推断出与SQL相关的一些知识点,并假定文档内容是关于SQL常见问题解答的,从而为您构建一个关于SQL的详细知识点说明。以下是根据这一假设而生成的SQL知识点: 1. SQL基础:SQL...

    JAVA解惑.pdf

    7. **泛型**:泛型是Java 5引入的一个重要特性,它可以提供类型安全的容器,防止在容器中存储不兼容的数据类型。泛型的使用可以提高代码的可读性和可维护性。 8. **接口与抽象类**:Java中的接口是完全抽象的,定义...

    IT解惑(IT学生解惑真经、程序员羊皮卷、高质量c编程指南)

    《IT解惑》是一部综合性的资源集合,包含了《IT学生解惑真经》、《程序员羊皮卷》和《高质量C编程指南》三部分,旨在为计算机科学与技术的学习者和未来的职业程序员提供全面的指导和建议。这些文档分别关注了IT学生...

    c语言解惑.pdf

    同时,查阅相关的文档和资料,如C语言的标准库文档,也是解决问题的一个重要手段。 总之,C语言解惑不仅仅是为了应对特定的难题,更是通过解决这些难题来提升自身的编程思维和技能。在学习的过程中,要注重动手实践...

    "java解惑" PDF版本

    "java解惑" PDF版本

    SQL解惑(第2版)

    一个好的SQL解决方案需要考虑的因素包括但不限于代码的可读性、性能优化、事务处理、并发控制、容错能力等。《SQL解惑》通过展示多种解决方案,帮助程序员理解和掌握这些问题,并指导他们如何灵活运用SQL语言来满足...

    java解惑java解惑java解惑

    在Java的世界里,疑惑可能涵盖语法、类库、框架、并发、内存管理等多个方面。下面,我们将深入探讨一些常见的Java解惑知识点。 1. **Java基础** - **变量与数据类型**:Java支持基本数据类型(如int、double等)和...

Global site tag (gtag.js) - Google Analytics