是否有任何设计模式可根据设备类型在数据之间切换?

时间:2013-02-01 09:41:43

标签: java design-patterns spring-mvc spring-mobile

我们有一个基于Spring MVC的Web应用程序。现在我们需要修改此应用程序,以便在智能手机上正确呈现。

为此,我们将为智能手机创建单独的JSP。因此,请求来自浏览器,我们将检查请求是否来自桌面然后我们将显示 普通的JSP,或者如果请求来自移动设备,那么我们将展示用于智能手机的JSP。

我们将使用spring Mobile。

在某些情况下,我们还希望限制智能手机上的数据。我们可能不会在JSP中显示所有数据。

e.g。我们可能需要在菜单中只显示几个项目。桌面Web应用程序将显示完整菜单,而智能手机将显示较少的菜单项。即使我们将为桌面菜单和移动菜单使用不同的JSP,菜单项也来自数据库。

是否有任何设计模式可以帮助我们?我们不想写那些if else条件来检查设备类型。

7 个答案:

答案 0 :(得分:1)

如果从UI的角度看菜单问题,则可以使用Abstract Factory设计模式。通常,您将拥有一个生成菜单的通用界面:

interface MenuFactory {
    Object createMainMenu();
    Object createSomeOtherMenu();
}

和两个实现:

public class DesktopAppMenuFactory implements MenuFactory {
    public Object createMainMenu() {
         ask dao for menus intended for desktop variant
         return ...
    }

    public Object createSomeOtherMenu() {
         ask dao for menus intended for desktop variant
         return ...
    }
}

public class MobileAppMenuFactory implements MenuFactory {
    public Object createMainMenu() {
         ask dao for menus intended for mobile variant
         return ...
    }

    public Object createSomeOtherMenu() {
         ask dao for menus intended for mobile variant
         return ...
    }
}

然后编写一个方法,创建适当的工厂给定客户端类型:

public static MenuFactory createMenuFactory(String clientType) {
    if( clientType is desktop.. ) {
        return new DesktopAppMenuFactory();

    } else if( clientType is mobile.. ) {
        return new MobileAppMenuFactory();
    }
}

并在您的控制器和JSP中使用MenuFactory,而不会打扰它的变体。这个唯一的if语句在ebove实用方法createMenuFactory()中。

另一方面,如果从数据的角度看问题,那么应用于服务层的Strategy Pattern将是合适的。但是代码代码最终与上面的代码非常相似,*Factory重命名为*Service,实现被称为策略而不是工厂。

答案 1 :(得分:1)

查看the Sitemesh framework一个轻量级且灵活的Java Web应用程序框架,该框架应用Gang of Four装饰器模式,以便将内容与演示文稿完全分离

下面是一个示例,向您展示如何使用它。


配置

的pom.xml

<dependency>
    <groupId>opensymphony</groupId>
    <artifactId>sitemesh</artifactId>
    <version>2.4.2</version>
</dependency>

WEB-INF / web.xml中

<filter>
    <filter-name>sitemeshFilter</filter-name>
    <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>sitemeshFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

WEB-INF / sitemesh.xml

<?xml version="1.0" encoding="UTF-8" ?>
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/sitemesh-decorators.xml" />
    <excludes file="${decorators-file}" />
    <page-parsers>
       <parser content-type="text/html" class="com.opensymphony.module.sitemesh.multipass.DivExtractingPageParser"/>
    </page-parsers>
    <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
            <param name="decorator.parameter" value="decorator" />
        </mapper>
        <mapper
            class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
            <param name="decorator" value="none" />
            <param name="parameter.name" value="printable" />
            <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
            <param name="property.1" value="meta.decorator" />
            <param name="property.2" value="decorator" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
            <param name="config" value="${decorators-file}" />
        </mapper>
    </decorator-mappers>
</sitemesh>

WEB-INF /的sitemesh-decorators.xml

<?xml version="1.0" encoding="UTF-8" ?>
<decorators defaultdir="/WEB-INF/sitemesh">
    <decorator name="mobile" page="mobile.jsp" />
    <decorator name="tablet" page="tablet.jsp" />
    <decorator name="desktop" page="desktop.jsp" />
    <excludes>
        <pattern>*.html*</pattern>
        <pattern>*.json*</pattern>
        <pattern>*.xml*</pattern>
        <pattern>*.download*</pattern>
    </excludes>
</decorators>

模板

WEB-INF /的sitemesh / mobile.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Mobile Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="mobile">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

WEB-INF /的sitemesh / tablet.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Tablet Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="tablet">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
                <li>Menu 3</li>
                <li>Menu 4</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

WEB-INF /的sitemesh / desktop.jsp

<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" 
%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><!DOCTYPE HTML>
<html>
    <head>
        <title>Desktop Template - <decorator:title /></title>
    </head>
    <body>        
        <nav class="desktop">
            <ul>
                <li>Menu 1</li>
                <li>Menu 2</li>
                <li>Menu 3</li>
                <li>Menu 4</li>
                <li>Menu 5</li>
                <li>Menu 6</li>
            </ul>
        </nav>
        <div id="wrapper">
            <decorator:body />
        </div>
    </body>
</html>

映射

HomeController.java

@RequestMapping("/")
public String home(Device device) {
    if (device.isMobile()) {
        return "mobile/home/index";
    } else if (device.isTablet()) {
        return "tablet/home/index";
    } else {
        return "desktop/home/index";       
    }
}

WEB-INF /视图/移动/家/ index.jsp的

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="mobile" />
    <title>Mobile Home Page</title>
</head>
<body>
    <p>Mobile Page Content</p>
</body>

WEB-INF /视图/片/家庭/ index.jsp的

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="tablet" />
    <title>Tablet Home Page</title>
</head>
<body>
    <p>Tablet Page Content</p>
</body>

WEB-INF /视图/桌面/家/ index.jsp的

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
%><head>
    <meta name="decorator" content="desktop" />
    <title>Desktop Home Page</title>
</head>
<body>
    <p>Desktop Page Content</p>
</body>

答案 2 :(得分:1)

大多数其他建议的解决方案都是过度设计的,遵循Keep It Simple原则。

使用JSP生成XML格式的页面标准化抽象,根据客户端设备类型选择适当的不同样式表。这样可以保持内容与呈现的良好分离,而不会将自己与特定设备联系起来。

答案 3 :(得分:0)

如果您正在使用Spring 3 MVC,并且正常情况下使用Controller方法返回View,那么我认为最简单和最正确的方法是使用单独的方法来处理移动设备或者相同的方法,但返回一个不同的视图(通过你的视图解析器)。

因此,例如,我的方法可能会执行以下操作:

@RequestMapping
public String default(Model uiModel, HttpServletRequest request) {
  // Do common stuff here, like load your model

  if(request.getHeader("User-Agent").indexOf("Mobile") != -1) {
    return "normalForm";
  } else {
    return "mobileForm";
  }
}

你甚至可以根据一些预定义的模式动画并动态构建名称,比如iphone获取“form_iphone”而Chrome获得“form_chrome”。

答案 4 :(得分:0)

如果您打算将支持扩展到任何类型的设备,我会为此提供某种支持。我可以想一个简单的方法,但我假设很多(你的菜单是基于用户许可的例子来呈现的......)。

根据用户的当前设备更改用户的权限(桌面用户可以查看所有内容,移动用户拥有较少的权限,因此,在菜单上看不到一些itens)。您可以登录用户,并根据设备过帐他的权限。

可以在菜单表上添加一列或创建某种处理器以删除某些设备无法呈现的菜单元素。

答案 5 :(得分:0)

请记住智能手机有多种尺寸,这意味着两种视图都不够用。 看看HTML5。您甚至可能不需要两个视图。有一个响应式网页。响应式页面会自行调整大小以适应小型和大型外形。 例如:http://twitter.github.com/bootstrap/index.html。尝试重新调整上面链接中的页面大小。你可以有一个菜单,可以在较小的屏幕上压缩自己(或删除一些项目)。 如果触摸在您的应用程序中很重要,请查看触摸的java脚本框架。 另请参阅http://verekia.com/initializr/responsive-template

答案 6 :(得分:0)

如果您的主要目标是添加对移动网络的支持,我要考虑的另一种方法是让您的网站只有一个版本具有响应能力。

你可以通过许多css框架实现这一点,其中最受欢迎的是Twitter's Bootstrap

使用此方法,屏幕将相应调整大小,因为屏幕尺寸更小或更大。 您可以使用此示例查看流体布局:Bootstrap Fluid

这样您的网络应用会调整其布局及其内容(包括菜单和图片)的大小 这样它可用于多种屏幕尺寸。