MVC的困惑

刚看到一篇文章,叫“MVC的困惑”,说我们为什么要学习框架,现在大家有些盲目性,感觉写的挺好的!

在很多年前,我们这么写程序的


很多年前,那是一个贫苦的年代,如果我们要使用Java在网页上做一些动态的交互功能。很多人会告诉你一个技术,叫做JSP。在我还对Java非常困惑的时候,就有人告诉我,JSP是个好东西,它可以在HTML代码里面写Java代码来完成逻辑。



Html代码 复制代码



  1. %   

  2.      String name = request.getParameter(“name”);   

  3.      String password = request.getParameter(“password”);   

  4.   

  5.      UserHandler u

    serHandler = new UserHandler();   


  6.      if(userHandler.authenticate(name, password)) {   

  7. % 

  8. 恭喜你,登录成

     


  9. %   

  10.       } else {   

  11. % 

  12. 对不起,登录失败 

  13. %   

  14.       }   

  15. %  

作为一张JSP,它可以接收从别的JSP发送过来的登录请求,并进行处理。这样,我们不需要任何额外的配置文件,也不需要任何框架的帮忙,就能完成逻辑。


后来,我们放弃了在页面上写逻辑


后来,程序写得越来越多,我们发现,这种在HTML代码中编写Java代码来完成逻辑的方式存在着不少问题:

1. Java代码由于混杂在一个HTML环境中而显得混乱不堪,可读性非常差。一个JSP文件有时候会变成几十K,甚至上百K。要找一段逻辑,经常无法定位。

2. 编写代码时非常困惑,不知道代码到底应该写在哪里,也不知道别人是不是已经曾经实现过类似的功能,到哪里去引用。

3. 突然之间,某个需求发生了变化。于是,每个人蒙头开始全程替换,还要小心翼翼的,生怕把别人的逻辑改了。

4. 逻辑处理程序需要自己来维护生命周期,对于类似数据库事务、日志等众多模块无法统一支持。

在这个时候,如果有一个产品,它能够将页面上的那些Java代码抽取出来,让页面上尽量少出现Java代码,该有多好。于是许多人开始使用servlet来处理那些业务逻辑。



Java代码 复制代码



  1. public class LoginServlet extends HttpServlet {   

  2.   

  3.     /* (non-Javadoc)  

  4.      * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)  

  5.      */  

  6.     @Override  

  7.     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {   

  8.         String message = null;   

  9.         RequestDispatcher dispatcher = req.getRequestDispatcher(“/result.jsp”);   

  10.         String name = req.getParameter(“name”);   

  11.         String password = req.getParameter(“password”);   

  12.            

  13.         UserHandler userHandler = new UserHandler();   

  14.         if(userHandler.authenticate(name, password)) {   

  15.             message = “恭喜你,登录成功”;   

  16.         } else {   

  17.             message = “对不起,登录失败”;   

  18.         }   

  19.            

  20.         req.setAttribute(“message”, message);   

  21.         dispatcher.forward(req, resp);   

  22.     }   

  23. }  

在这里,我们需要在web.xml中为这个servlet配置url的请求关系。



Xml代码 复制代码



  1. <servlet>  

  2.   <servlet-name>Loginservlet-name>  

  3.     <servlet-class>  

  4.       com.demo2do.servlet.LoginServlet   

  5.   servlet-class>  

  6. servlet>  

  7. <servlet-mapping>  

  8.   <servlet-name>Loginservlet-name>  

  9.   <url-pattern>  

  10.     /Login   

  11.   url-pattern>  

  12. servlet-mapping>  

代码重构到这里,我们发现,其实我们的工作量本身并没有减少,只是代码从JSP移动到了Servlet,使得整个流程看上去稍微清楚了一些。然而,为了这么点干净,我们付出的代价是什么?为每个servlet都在web.xml里面去做一个url的请求配置!


再后来,出现框架


时代进一步发展,人们发现简单的JSP和Servlet已经很难满足人们懒惰的要求了。于是,人们开始试图总结一些公用的Java类,来解决Web开发过程中碰到的问题。这时,横空出世了一个框架,叫做struts。它非常先进地实现了MVC模式,成为了广大程序员的福音。

struts的代码示例我就不贴了,网上随便搜搜你可以发现一堆一堆的。在一定程度上,struts能够解决web开发中的职责分配问题,使得显示与逻辑分开。不过在很长一段时间内,使用struts的程序员往往无法分别我们到底需要web框架帮我们做什么,我们到底需要它完成点什么功能?


我们到底要什么


在回顾了我们写代码的历史之后,我们回过头来看看,我们到底要什么?

无论是使用JSP,还是使用Struts1,或是Struts2,我们至少都需要一些必须的元素(如果没有这些元素,或许我还真不知道这个程序会写成什么样子):

1. 数据

在这个例子中,就是name和password。他们共同构成了程序的核心载体。事实上,我们往往会有一个User类来封装name和password,这样会使得我们的程序更加OO。无论怎么说,数据会穿插在这个程序的各处,成为程序运行的核心。

2. 页面展示

在这个例子中,就是login.jsp。没有这个页面,一切的请求、验证和错误展示也无从谈起。在页面上,我们需要利用HTML,把我们需要展现的数据都呈现出来。同时我们也需要完成一定的页面逻辑,例如,错误展示,分支判断等等。

3. 处理具体业务的场所

在这里,不同阶段,处理具体业务的场所就不太一样。原来用JSP和Servlet,后来用Struts1或者Struts2的Action。

上面的这些必须出现的元素,在不同的年代,被赋予了不同的表现形式,有的受到时代的束缚,其表现形式非常落后,有的已经不再使用。但是拨开这些外在的表现形式,我们就可以发现,这不就是我们已经熟门熟路的MVC嘛?

数据 ———— Model
页面展示 ———— View
处理具体业务的场所 ———— Control

所以,框架不重要,概念是王道。只要能够深刻理解MVC的概念,框架对你来说,只是一个jar包而已。

   早上安装计划把622的作业完成了,学会了在catch块中做更多的事情:就是利用while循环,比如:

public class Recover {
  protected int current = 0;
  protected boolean accept = false;
  public Recover() {}
  public Recover(int cur) {
    current = cur;
  }
  public void increment() {
    ++current;
  }
  public boolean passed() {
    return accept;
  }
  public void passing() throws NotBigEnoughException {
    if (current > 2) {
      accept = true;
      System.out.println(“accept ” + current);
    } else
      throw new NotBigEnoughException(“reject ” + current);
  }
  public static void main(String[] args) {
    Recover re = new Recover();
    while (!re.passed()) {
      try {
       re.passing();
      } catch (NotBigEnoughException e) {
       System.out.println(e);
       re.increment();
      }
    }
  }
}

  在定义方法是抛出异常,然后在异常中处理!代码很容易理解,但传递的思想比较有意义!不过这样的话还是有点用Exception来做流程控制的嫌疑,呵呵!好吧,不管怎么样,又学会一种方法!
  玩了会飞行棋,win!
  下午把622的类图画了一下,但是怎么清晰的划分系统的各个部分还是没有思路,decouple之路漫漫长呀,sigh!
  又玩了好久侍魂!!!damned!完了我。。。
  去了趟超市回来怀着愧疚的心情赶紧再把facade模式巩固一下! 
  按照计划明天该开始着手621的project了,不能拖了!

一、门面模式定义

      外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。举个例子:在做项目或产品的过程中进行跨部门合作的时候,每个部门都有个相应的接口人,那么我们只需和对应部门的接口人交互即可,门面模式也一样,门面模式提供一个高层次的接口,使得子系统更易于使用。

二、 门面模式的结构

  门面(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。

三、特点

子系统的独立性: 子系统对外提供一个统一简单的接口,可以减少系统间的耦合性,提高子系统的独立性和可移植性。
系统的层次性:在构建一个层次化的系统时,可以使用 Facade 模式定义系统中每一层的入口。如果层与层之间是相互依赖的,则可以限定它们仅通过 Facade 进行通信,从而简化层与层之间的依赖关系

假设有一个保安系统,由2个camera,3个light,1个sensor,1个alarm组成。保安系统的客户端,即工作人员需要将这些仪器打开或者关闭。

如果不适用Facade模式,代码为:

public class  Client
{
    static private Camera camera1,camera2;
    static private Light light1,light2,light3;
    static private Sensor sensor;
    static private Alarm alarm;
    public static void main(String[] args)
    {
        camera1.turnOn();
        camera2.turnOn();
        light1.turnOn();
        light2.turnOn();
        light3.turnOn();
        sensor.activate();
        alarm.activate();
    }
}

如果使用了Facade模式,代码为:
public class  Facade
{
    private Camera camera1,camera2;
    private Light light1,light2,light3;
    private Sensor sensor;
    private Alarm alarm;
    public void active()
    {
        camera1.turnOn();
        camera2.turnOn();
        light1.turnOn();
        light2.turnOn();
        light3.turnOn();
        sensor.activate();
        alarm.activate();
    }
}

public class Client
{
&nbs
p;   private static Facade facade;
    public static void main(String[] args)
    {
        facade.active();
    }
}
客户端代码少了很多

四、总结

    从客户程序的角度来看, Facade模式不仅简化了整个组件系统的接口,同时对于组件内部与外部客户程序来说,从某种程度上也达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Façade接口的变化。

    Façade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Façade很多时候更是一种架构设计模式。

    注意区分Façade模式、Adapter模式、Bridge模式与Decorator模式。Façade模式注重简化接口,Adapter模式注重转换接口,Bridge模式注重分离接口(抽象)与其实现,Decorator模式注重稳定接口的前提下为对象扩展功能。

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s