您也是打痛苦混战的高手吗?

本文探讨了软件开发中“混战高手”的概念,即开发者倾向于重复编写相似代码而非复用,提出通过企业逻辑模型和元数据驱动架构(MDA/DDA/ECO)等方法实现代码复用和技术标准化。

您也是打痛苦混战的高手吗?

我喜欢下围棋,虽然我没有太多的时间精进我的棋艺。以前看棋谱或是看一些围棋的故事时经常会看到一些叙述文字说某些围棋高手是打混战的高手,这是说围棋局面愈乱拥有这种特质的围棋高手就愈容易胜出。NBA也是一样,每年我都和一些好友玩Fantasy NBA,也喜欢看NBA球赛,一些NBA好手也是打混战的高手,这也是局势愈混乱,比分愈接近的时候这些NBA球员就表现得愈好。

但是很不幸的,在软件开发方面如果我们说某人是打混战的高手,那么我就不知道这是恭维还是暗讽。什么是软件开发打混战的高手? 想想您写过多少似曾相识的程序代码? 许多软件开发打混战的高手在写程序代码时非常的快速,脑筋更是运转得快得不得了,因此当他们需要一些程序代码时,往往不愿意花时间想想或是找找是不是已经有了可供使用的程序代码,就很快的再写了一次,因为他们觉得再写一次更快。或是当他们在写COM+.NETJava时,许多中间的程序代码都大同小异,只是因为程序语言的不同或是使用的技术不同,就再写一次。

另外的情形则不一定是软件开发打混战的高手,而应该说是一个团队中的成员所发生的事情。例如:在一个软件开发团队中,AB在写自己的应用程序时,AB都可能同时在撰写类似的程序代码,例如A可能写了select * from employee,而B也正写select e.ID, e.Name, … from employee e。或是A需要一个方法叫做GetSeminarQA以便得到研讨会所有的QA问题,而B也在写类似的方法,只是A使用Delphi程序语言,而B则使用Java。许多有对项目开发有经验的人都知道,一旦当项目完成(或是完成不了)之后,如果使用Audit/Metric工具来检查项目程序代码,就会发现许多,许多类似的程序代码不断地出现在项目的不同的程序中。

也许重构正是因为那些聪明的人在检视了以往的程序代码之后发现原来自己正是打混战的高手因此而发展出来的技术。

混战高手需要改变吗? 我也不知道,各人爱好不同,让我们看看下面的一个企业逻辑模型。DevCoSeminar类别定义了三个方法,其中的GetClosedQAs方法可以回传一个研讨会所有的QA问题,那么我们应该如何实作GetClosedQAs?

 

如果这去问Java的朋友,他们会用Java + JDBC或是Java + Hibernate来实作,如果询问C#的朋友,他们马上会用C#+ADO.NET在数秒之内完成,Delphi? 那选择更多了,Delphi+dbExpressDelphi+ADODelphi+,,,VB? PHP? Python? 嗯这个问题太简单了,许多人也许不根本不屑一顾。

但是仔细看看上面的模型,不管使用JavaC#Delphi或是其它的程序语言,上面的企业逻辑规则都是一样的,不会因为选择的程序语言不同而改变,最多是实作方法不同的,那么您也许会问然后呢?

让我们换个角度想想,如果我们在企业逻辑模型中就完成GetClosedQAs方法呢?

看看下面的图形,我在GetClosedQAsBody特性值中直接使用了OCL来撰写GetClosedQAs方法。为什么要使用OCL? 因为这个企业逻辑规则是一样的,不会因为客户端的程序语言,平台或是技术而改变。

 

有了上面的企业逻辑模型之后,对于开发人员人说仍然必须搞清楚如何在客户端使用企业逻辑模型,这不困难,让我们爱挥一下技术人员的天赋,追根究底的往下挖。

一旦在企业逻辑模型中定义了GetClosedQAs之后,ECO会自动产生如下的程序代码:

    [UmlTaggedValue('Eco.Body', 'self.hasQA->select(closed)->asSet()')]

    function getClosedQAs: System.&Object;

ECO使用了.NET的属性来定义DevCoSeminar类别的getClosedQAs方法。再往下看,getClosedQAs的实作如下:

function DevCoSeminar.getClosedQAs: System.&Object;

type

  TArrayOfobject = array of &object;

begin

  Result := (System.&Object(Self.AsIObject.Invoke('getClosedQAs', New(TArrayOfobject, 0))));

end;

嗯,getClosedQAs呼叫了IObjectInstanceInvoke来执行'getClosedQAs',回传的结果是一个包含执行结果对象的对象数组,。而IObjectInstance有如下的定义:

    public interface IObjectInstance: IObject

    {

        IObjectStateMachine StateMachine { get; }

        object Invoke(IMethod method, object[] parameters);

        object Invoke(string methodName, object[] parameters);

        object Invoke(IMethod method, IElement[] parameters);

    }

OK,很好,现在只要我们搞清楚如何撷取出getClosedQAs回传的结果就可以取得依照企业逻辑模型定义的getClosedQAs方法的运算结果。下面的程序代码就是使用Delphi做为客户端程序语言来存取执行的结果:

procedure TWinForm.btnQAs_Click(sender: System.Object; e: System.EventArgs);

var

  aSeminar : DevCoSeminar;

  anObject : System.&Object;

begin

  aSeminar := Self.cmhSeminar.Element.AsObject as DevCoSeminar;

  anObject := aSeminar.getClosedQAs;

  HandleQAs(anObject);

end;

现在唯一的难题就是如何从getClosedQAs方法回传的型态为System.Object的结果值出运算结果。在这里让我给使用ECO的朋友一个暗示,对于像getClosedQAs方法执行OCL并且回传结果对象串行的方法,这个回传的结果都实作了ICollection接口,因此我们只需要把执行结果转变型态为ICollection接口就可以使用Delphifor…in循环或是C#foreach循环取得结果,例如下面的程序代码就范例了从getClosedQAs的对象串行中取出所有符合条件的QA对象:

procedure TWinForm.HandleQAs(anObject: System.&Object);

var

  aQA : QA;

begin

  for aQA in (anObject as ICollection) do

  begin

    Self.lbResult.Items.Add(aQA.Question);

  end;

end;

执行一下上面的程序代码,我们就可以顺利的得到正确的结果,下图就是一个范例应用程序的执行结果画面:

 

对于C#的朋友,程序代码和Delphi是一样的,关键在企业逻辑模型,任何的客户端程序语言都可以重复使用企业逻辑模型中的设计:

private void button1_Click(object sender, System.EventArgs e)

{

  DevCoSeminar aSeminar = cmhSeminar.Element.AsObject as DevCoSeminar;

  System.Object anObject = aSeminar.getClosedQAs();

  HandleQAs(anObject);

}

 

我还是要问,您感觉到了什么? 是继续让独自的开发人员在不同的程序代码中仍然撰写各自的程序代码? 为每一个类似的情形不断的撰写重复的程序代码? 为不同的程序语言不断的撰写重复的程序代码? 为不同的平台不断的撰写重复的程序代码? 我想这没有标准的答案,每个人的风格不同,有人永远是打混战的高手,有人却能够在知道了新的选择之后开始思考这些新的选择会或是可以带来什么改变。

也许学习MDA/DDA/ECO的价值之一是开始让我们思考新的选择以及新的选择可能带来的影响是什么!

 

 
<think>嗯,用户之前已经询问过如何使用MVC模式,我给出了一个比较详细的例子,特别是以二手图书系统为例。现在用户的新问题是:“不懂,这个mvc模式里面的层是个什么东西,自己创建的文件夹吗?”看起来用户对于“层”在MVC中的具体含义和实际项目中的组织方式不太理解。 首先,我需要确认用户的问题核心。用户可能将“层”理解为物理上的文件夹结构,而实际上MVC中的层更多是逻辑上的划分,但确实在项目中会通过文件夹来组织代码。所以需要解释清楚逻辑分层和物理文件夹的关系。 接下来,用户可能对MVC各层的职责还有疑惑,特别是在代码中的具体体现。之前的回答中提到了Model、View、Controller的分工,但用户可能没有完全理解这些层在项目中的具体位置和如何创建。 考虑到用户可能是一个刚开始学习编程的新手,或者对MVC概念不太熟悉,需要用更简单易懂的语言来解释。避免使用太多专业术语,用类比的方式帮助理解。例如,把MVC的三个部分比作餐厅的不同角色,这样用户更容易联想。 然后,需要具体说明在项目中如何通过创建文件夹来组织这些层。例如,在Java Web项目中,通常会创建不同的包(package)来存放Model、DAO、Service、Controller等类,而View层可能是JSP或HTML文件放在WebContent目录下。需要明确说明文件夹结构,并给出例子,让用户知道实际项目中应该如何组织代码。 另外,用户可能对代码示例中的路径和包结构不太理解,比如“src/com/example/model/Book.java”这样的路径。需要解释这些路径对应的是项目中的源代码目录,不同的文件夹对应不同的逻辑层,并说明每个文件的作用。 还需要强调分层的好处,比如解耦、复用性和可维护性,但要用具体的例子来说明。例如,修改界面不会影响业务逻辑,或者数据库更换时只需修改DAO层,而不需要改动其他部分。 同时,用户之前的回答中提到了DAO、Service等层,可能需要进一步解释这些层在MVC中的位置。例如,DAO属于Model层的一部分,负责数据访问,而Service层处理业务逻辑,Controller负责协调。需要明确这些子层的职责,避免混淆。 最后,要确保回答结构清晰,分点说明,让用户能够一步步理解。可能需要使用比喻、实际项目结构示例和简单明了的解释来帮助用户建立MVC分层的概念,并理解如何在项目中通过创建文件夹来实现这种分层。</think>### 通俗解释:MVC 中的「层」究竟是什么? --- #### **一、「层」的本质是代码分类方式** **不是单纯的文件夹**,而是**逻辑功能分组**,但实际开发中会**通过创建文件夹来实现分层**。 好比整理衣柜时,你会把: - 上衣放在 **/上衣** 层(对应 Model) - 裤子放在 **/裤子** 层(对应 View) - 配饰放在 **/配饰** 层(对应 Controller) --- #### **二、具体到代码项目中的体现(Java 示例)** ##### **1. 文件夹结构示例** ```bash 项目根目录 ├── src # 源代码 │ ├── com/example │ │ ├── model # Model层:数据实体(图书、用户等) │ │ ├── dao # Model子层:数据库操作(查书、存订单) │ │ ├── service # Model子层:业务逻辑(计算运费、库存检查) │ │ └── controller # Controller层:接收请求(处理搜索、下单) ├── WebContent # View层 │ ├── WEB-INF │ │ └── jsp # JSP页面(显示图书列表、订单详情) │ └── css # 样式文件 ``` ##### **2. 关键分层对比** | 层级 | 对应内容 | 实际文件夹案例 | 类比现实场景 | |--------------|------------------------------|-----------------------|-------------------------| | **Model** | 数据类 + 数据库操作 + 业务逻辑 | `src/com/example/model` | 图书馆的藏书库和借阅规则 | | **View** | 网页/JSP/前端模板 | `WebContent/jsp` | 图书馆的展示书架和检索机 | | **Controller**| 处理请求的Java类 | `src/com/example/controller` | 图书馆的前台服务台 | --- #### **三、为什么需要分层?** 1. **分工明确** - 后端程序员专注写 `Model` 层(数据处理) - 前端程序员专注写 `View` 层(界面美化) - 全栈程序员协调 `Controller` 层(流程串联) 2. **修改隔离** - 修改数据库表结构时,只需调整 `model` 和 `dao` 文件夹里的代码 - 改版网页样式时,只需修改 `WebContent/jsp` 里的文件 3. **防止代码混战** 错误示范:在 JSP 页面里直接写 SQL 查询(相当于在书架上直接修改藏书) --- #### **四、新手常见问题解答** **Q1:必须严格按照这个文件夹结构吗?** - 不是强制要求,但**推荐遵循标准结构**,方便团队协作 - 小型项目可以简化(例如把 dao 和 service 合并到一个包里) **Q2:前端框架(Vue/React)算哪一层?** - 属于 **View 层的扩展**,替代传统 JSP - 此时 `WebContent` 可能改为 `src/main/resources/static` 存放前端代码 **Q3:Spring 框架中的 MVC 有何不同?** - 核心思想一致,但实现更便捷 - `@Controller` 注解替代 Servlet - `Service` 层自动注入 - `resources/templates` 代替 JSP --- #### **五、实操建议** 1. **创建项目时先搭骨架** ```bash mkdir -p src/com/example/{model,dao,service,controller} mkdir -p WebContent/{WEB-INF/jsp,css,js} ``` 2. **开发顺序推荐** Model → DAO → Service → Controller → View (从底层数据逐步向上开发) 3. **快速验证分层是否合理** 尝试回答:**「如果要更换数据库,需要改哪些文件?」** → 正确答案:只修改 `dao` 文件夹里的实现类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值