显示标签为“java”的博文。显示所有博文

使用策略模式,注意以下三个设计原则: 

1,找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2,针对接口编程,而不是针对实现编程。
3,多用组合,少用继承。

定义:
【策略模式】定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

用正则表达式,主要看这个字符串是否为以下三种关键字组成:
负数符号,数字,小数点。
而且负数符号和小点数不允许出现多个。
满足上述条件按,则为数字,不满足,为判断为不是数字。

if (!(((val.matches("[0-9]+\\.[0-9]+") || val.matches("\\-[0-9]+\\.[0-9]+"))) || val.matches("[0-9]+") || val.matches("-[0-9]+"))) {
System.out.println("不是数字");
}else {
System.out.println("是数字");
}

/**
* Cobol to java Convertion FrameWork test Programe
* @version $Revision: 1.0 2009/11/14
* @author nec gaoyu
*
* 変更履歴
* NO   日付      担当者         対応種類          対応内容
* 01  2009/11/14 高 禹 仕様変更         IR-AA-T2-0052
*/

浮点数值不适用于禁止出现舍入误差的金融计算中。例如,命令System.out.println(2.0-1.1)将打印出0.89999999999999,而不是人们希望的0.9。


出现这种问题的主要原因在于浮点数值是采用二进制系统表示的,而在二进制系统中无法精确的表示分数1/10。这就好像十进制无法精确的表示1/3一样。如果需要在数值计算中不含有任何舍入误差,就应该使用BigDecimal类。

另一个问题:请尝试用Google检索599,999,999,999,999-599,999,999,999,998。

得到上面错误计算结果的原因与浮点运算有关。由于计算机的工作是采用二进制形式,它只能以近似的方法表达某个十进制实数,这个实数由一个整数或定点数(即尾数)乘以2的整数次幂得到。以双精度浮点运算为例,64位存储空间能表达的实数范围为-2^63+1到+2^63-1。64位中52位代表尾数(实际的数),11位代表指数(有多少个零)。Google的错误显示它的计算器实际使用的尾数比正常的52位尾数要少。

TechRadar举了一个例子来说明简单的计算,误差的累积如何演变成生死攸关的灾难。 1991年2月25日,海湾战争结束前三天,伊拉克发射了飞毛腿导弹袭击美国在沙特阿拉伯的飞机场。为了计算导弹将飞往何处,美军的爱国者导弹防御系统需要知道系统时间。在启动之后,系统是以0.1秒间隔储存数据。但不幸的是,0.1秒不能精确的表示成二进制数。因此在爱国者导弹系统使用的24位寄存器中它会溢出一个小数。在导弹攻击时,系统已运行了100小时,或3,600,000嘀嗒,微小的错误逐渐累积成0.3433秒的误差,这段时间内飞毛腿导弹可以飞行687米。爱国者的雷达指向了错误的方向,没有发现目标,因此没有发射导弹拦截,导致28人付出了生命。

1,$ java -verbose:gc <クラス名>


可以查看JAVA运行时是否发生了垃圾回收。
「GC」 : Scavenge GC
「Full GC」 : Full GC

2,-Xms<> -Xmx<>
可以指定JVM的堆栈大小。、
-Xms512m : 堆栈最小为512M。
Xmx512m : 堆栈最大为512M。

private static final String ZERO_PADDING_PROP_FILE = "JSMI_QueryZeroPadding";


protected String formatForQuery(TrBigDecimal inData, String key) {
try {
ResourceBundle prop = ResourceBundle.getBundle(ZERO_PADDING_PROP_FILE);
if ("0".equals(prop.getString(key))) {
return String.valueOf(inData.getValue());
} else {
return inData.appendSpaces();
}
} catch (MissingResourceException e) {
return inData.appendSpaces();
}
}

如上所示:使用ResourceBundle.getBundle读取配置文件后进行逻辑处理。JSMI_QueryZeroPadding为放置在同名文件包下的文件名。后缀为properties。

JAR里面设定MAIN。然后用下面的命令:

java -jar name.jar
可以执行JAR。

如果希望将一个数组的值拷贝到另外一个数组中去,也就是所谓的深拷贝,JAVA的实现方式可以使用System类的arraycopy方法。调用这个方法的语法格式为:

System.arraycopy(from, fromIndex, to, toIndex, count) ;

数组to必须有足够的空间来存放拷贝的元素。

数组排序:可以使用Arrays类中的sort方法:
int[] a = new int[1000] ;
...
Arrays.sort(a) ;
这个方法是用了优化的快速排序算法。

判断两个数组是否相等(两个数组的长度相同,并且下标相同的元素都对应相等,则返回true)
Arrays.equals(type[] a , type[] b) ;

另外,数组还可以使用二分搜索法查找值v。如果找到,可以返回数组下标;否则,返回一个负值r; -r~1为保持有序v应插入的位置。
java.util.Arrays
static int binarySearch(type[] a, type v) ;

还有一个方法,是将一个数组所有的元素设置为v。
static void fill (type[] a, type v) ;

PMD 包含 16 个规则集,涵盖了 Java 的各种常见问题,其中一些规则要比其他规则更有争议:

基本(rulesets/basic.xml)—— 规则的一个基本合集,可能大多数开发人员都不认同它: catch 块不该为空,无论何时重写 equals(),都要重写 hashCode(),等等。

命名(rulesets/naming.xml)—— 对标准 Java 命令规范的测试:变量名称不应太短;方法名称不应过长;类名称应当以小写字母开头;方法和字段名应当以小写字母开头,等等。

未使用的代码(rulesets/unusedcode.xml)—— 查找从未使用的私有字段和本地变量、执行不到的语句、从未调用的私有方法,等等。

设计(rulesets/design.xml)—— 检查各种设计良好的原则,例如: switch 语句应当有 default 块,应当避免深度嵌套的 if 块,不应当给参数重新赋值,不应该对 double 值进行相等比较。


导入语句(rulesets/imports.xml)—— 检查 import 语句的问题,比如同一个类被导入两次或者被导入 java.lang 的类中。

JUnit 测试(rulesets/junit.xml)—— 查找测试用例和测试方法的特定问题,例如方法名称的正确拼写,以及 suite() 方法是不是 static 和 public。


字符串(rulesets/string.xml)—— 找出处理字符串时遇到的常见问题,例如重复的字符串标量,调用 String 构造函数,对 String 变量调用 toString() 方法。

括号(rulesets/braces.xml)—— 检查 for、 if、 while 和 else 语句是否使用了括号。

代码尺寸(rulesets/codesize.xml)—— 测试过长的方法、有太多方法的类以及重构方面的类似问题。

Javabean(rulesets/javabeans.xml)—— 查看 JavaBean 组件是否违反 JavaBean 编码规范,比如没有序列化的 bean 类。

终结函数(finalizer)—— 因为在Java语言中,finalize()方法不是那么普遍(我上次编写这个代码也经是好多年前的事了),所以它们的使用规则虽然很详细,但是人们对它们相对不是很熟悉。这类检查查找 finalize() 方法的各种问题,例如空的终结函数,调用其他方法的 finalize() 方法,对 finalize() 的显式调用,等等。

克隆(rulesets/clone.xml)—— 用于 clone() 方法的新规则。凡是重写 clone() 方法的类都必须实现Cloneable,clone()方法应该调用super.clone(),而 clone()方法应该声明抛出 CloneNotSupportedException 异常,即使实际上没有抛出异常,也要如此。

耦合(rulesets/coupling.xml)—— 查找类之间过度耦合的迹象,比如导入内容太多;在超类型或接口就已经够用的时候使用子类的类型;类中的字段、变量和返回类型过多等。

严格的异常(rulesets/strictexception.xml)—— 针对异常的测试:不应该声明该方法而抛出 java.lang.Exception异常,不应当将异常用于流控制,不应该捕获 Throwable,等等。

有争议的(rulesets/controversial.xml)—— PMD 的有些规则是有能力的Java程序员可以接受的。但还是有一些争议。这个规则集包含一些更有问题的检验,其中包括把null赋值给变量、方法中有多个返回点,以及从 sun 包导入等。

日志(rulesets/logging-java.xml)—— 查找 java.util.logging.Logger 的不当使用,包括非终状态(nonfinal)、非静态的记录器,以及在一个类中有多个记录器。

/**Action类
Struts1要求Action类继承一个抽象类,Struts1使用抽象类编程而不是接口
Struts2可以实现Action接口也可以不实现,Struts2提供一个ActionSuport基类去实现常用接口。Action接口不是必须的,任何有execute的标识的POJO都有可能成为struts2的Action的对象

/**线程模式
Struts1的Action是单例模式并且是线程安全的,仅有Action一个实例来处理所有请求。单策略模式限制了Struts1 Action能做的事。比且在开发时要注意Action资源必须是线程安全比且是同步的。
Struts2的Action对象为每个请求产生一个实例,因此没有线程安全问题。

/**Servlet依赖
Struts1 Action依赖与Servlet API,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execute方法。
Struts2 Action不依赖与容器,允许Action脱离容器被单独测试。如果需要,struts2依然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServletRequest和HttpServletResponse的必要性。

/**可测性:
测试Struts1 Action的一个主要问题是execute方法暴漏了Servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)
struts2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

/**捕获输入:
struts1使用ActionForm对象捕获输入。所有ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的基类不或输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有沉余的JavaBean)。

Struts2直接使用Acrtion属性作为输入属性,消除了对第二个输入对象的请求。输入属性可能是有自己(子)属性的Rich对象类型。Action属性能过通过web页面上的Taglibs访问。struts2也支持ActionForm模式。Richard对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven特性简化了Taglib对POJO输入对象的引用。

/**表达式语言
Struts1整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很脆弱。
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--“object graph Notation Language”(OGNL)

/**绑定值到页面(view)
Struts1使用标准JSP机制吧对象绑定到页面中来访问。
struts2使用ValueStack技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重同页面(view)

/**类型转换
Struts1 ActionForm属性通常都是String类型。struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
struts2 使用OGNL进行类型转换,提供基本和常用对象的转换器。

/**效验
Struts1支持在ActionForm的validate方法中手动效验,或者通过Commons Validator的扩展来效验。同一个类可以有不同的效验内容,但不能效验子对象。
Struts2支持通过validate方法和XWork效验框架进行效验。XWork效验框架使用为属性类类型定义的效验和内容效验,来支持Chain效验子属性。

/**Action执行的控制
Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不能的生命周期。堆栈能够根据需要和不同的Action一起使用。

定义:
提供一个创建一系列相关或者相互依赖对象的接口,而无需制定它们具体的类。抽象工厂(Abstract Factory)模式又成为Kit模式,属于对象创建型模式。

抽象工厂模式与工厂方法模式最大的区别在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则针对的是多个产品等级结构。正因为如此,在抽象工厂模式中经常会用到产品族(Product Family)这一概念,它指的是位于不同的产品等级结构中,并且功能相互关联的产品系列。

应用情景:
1,系统需要屏蔽有关对象如何创建,如何组织和如何表示。
2,系统需要由关联的对个对象来构成。
3,有关联的多个对象需要一起应用并且它们的约束是强迫的(不可分离)。
4,你想提供一组对象而不显示它们的实现过程,只显示它们的接口。

跟我学习设计模式之第二篇:工厂方法模式开篇了。下面我们来看看其定义:

工厂方法模式又称工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,属于类的创建型模式。在工厂方法模式中,父类负责定义创建对象的公共接口,而子类则负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成,即由子类来决定究竟应该实例化(创建)哪一个类。

下面以一个JAVA实例应用来看了解一下具体需求:
现实中不同品牌的手机应由不同的工厂制造,下面应用工厂模式来解决这个问题。

手机接口:
public interface Mobile {
public void call();
}

手机工厂接口:
public interface MobileFactory {
public Mobile productMobile();
}

摩托罗拉手机实现手机接口:
public class Motorola implements Mobile {
public void call() {
System.out.println("MOTOROLA モベイル");
}
}

诺基亚手机实现手机接口:
public class Nokia implements Mobile {
public void call() {
System.out.println("Nokia モベイル");
}
}

摩托罗拉工厂实现了生产手机的方法,返回摩托罗拉手机:
public class MotorolaFactory implements MobileFactory {

@Override
public Mobile productMobile() {
// TODO 自動生成されたメソッド・スタブ
System.out.print("Motorola工場で製造した");
return new Motorola();
}

}

诺基亚工厂实现了生产手机的方法,返回诺基亚手机:
public class NokiaFactory implements MobileFactory {

@Override
public Mobile productMobile() {
// TODO 自動生成されたメソッド・スタブ
System.out.print("Nokia工場で製造した");
return new Nokia();
}

}

客户程序:
public class Client {

/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
MobileFactory mf;
Mobile m;

mf = new MotorolaFactory();
m = mf.productMobile();
m.call();

mf = new NokiaFactory();
m = mf.productMobile();
m.call();
}

}

输出:
Motorola工場で製造したMOTOROLA モベイル
Nokia工場で製造したNokia モベイル

下面的情景很适合应用工厂方法模式:
1,类不知道自己要创建哪一个对象;
2,类用它的子类来制定创建哪个对象;
3,客户需要清楚创建了哪一个对象。

对设计模式的理解和应用能力,是区分一个程序员和一个软件工程师的重要特征。从今天开始,我将花费一些时间和精力,用在设计模式的学习和实践上。

今天,首先解决三个问题:
第一,什么是设计模式?
第二,设计模式的作用?
第三,设计模式的分类?

按照顺序依次解决这三个问题,就算完成开篇的内容。

第一,什么是设计模式?

模式的定义:模式是一种问题的解决思路,它已经试用于一个实践环境,并且可以适用于其他环境。

如果觉得抽象,举几个例子马上就可以理解了:用牛耕田,织网捕鱼,打井取水……,所有这些都是前人创造的生活模式,我们大家不自觉的把它们应用在生活的方方面面。

同理,程序设计,也有一些前人的设计思路可供我们直接使用,这就是设计模式。

第二,设计模式的作用?

1,重用设计,比重用代码更有意义,它会自动带来代码重用。
2,为设计提供共同词汇,模式名就是设计词汇,方便交流。
3,开发文档中采用模式词汇让阅读者更容易理解。
4,可以使得重构系统变得容易。确保代码正确,降低设计和实现中出现错误的可能性,为从写其它应用程序提供很好的系统架构。
5,正确使用设计模式,可以节省大量时间。

第三,设计模式的分类?

设计模式种类很多,包括分布式编程模式,用户界面模式,数据模式模式三大类。目前流行的面向对象设计模式,仅1995年“Gang of Four”(四位作者:Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides)描述的就有二十多种,称之为GoF模式,与其相对应的另一种重要的设计模式是通用责任分配软件系列模式(GRASP,General Responsibility Assignment Software Patterns)。

1,GRASP模式的分类:

与其说它是面向对象的设计模式,不如说它是面向对象的设计要求,细分为9种模式。模式之间不是独立的,存在相互平衡的制约关系,所以我们的设计只能努力的满足GRASP的各种模式。
1)Information Expert(信息专家)
2)Creator(创造者)
3)Low coupling(低耦合)
4)High cohesion)(高内聚)
5)Controller(控制器)
6)Polymorphism(多态)
7)Pure Fabrication(纯虚构)
8)Indirection(间接)
9)Protected Variations(受保护变化)

2,GoF模式的分类:

◆根据目的准则分类:
就是说,指定的模式用来完成什么工作。可分三种:
1)Creational(创建型):与对象创建有关
2)Structural(结构型):处理类或对象的组合
3)Behavioral(行为型):描述类或对象如何交互及如何分配职责。
◆根据范围准则分类:
即指定的模式是用于类还是用于对象,分为两种:
1)类模式:编译时就定下来了。
2)对象模式:处理对象间关系,这些关系具有动态性,在运行期间是可以变化的。

范围/目的:Creational(创建型): Creational(创建型): Behavioral(行为型)
类:Simple Factory:Adpter(class):Interpreter
:Factory Method: :Template method
对象:Abstract Facotry:Adapter(object):Chain of Responsibility
:Builder :Bridge :Command
:Prototype :Composite :Iterator
:Singleton :Decorator :Mediator
: :Facade :Memento
: :Flyweight :Observer
: :Proxy :State
: : :Strategy
: : :Visitor

一个用户的请求是通ActionServlet来处理和转发的。那么,ActionServlet如何决定把用户请求转发给哪个Action对象呢?这就需要一些描述用户请求路径和Action衍射关系的配置信息了。在Struts中,这些配置映射信息都存储在特定的XML文件Struts-config.xml中。在该配置文件中,每一个Action的映射信息都通过一个元素来配置。

这些配置信息在系统启动的时候被读入内存,供Struts在运行期间使用。在内存中,每一个元素都对应一个org.apache.struts.action.ActionMapping类的实例。

对于采用Struts框架的web应用,在web应用启动时就会加载并初始化ActionServlet,ActionServlet从struts-config.xml文件中读取配置信息,把它们存放到各个配置对象中,例如Action的映射信息存放在ActionMapping对象中。

当ActionServlet接收到一个客户请求时,将执行如下流程:

1.检索和用户请求相匹配的ActionMapping实例,如果不存在,就返回用户请求路径无效信息。

2.如ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中。

3.根据配置信息决定是否需要表单验证。如果需要验证,就调用ActionForm的Validate()方法。

4.如果ActionForm的Validate()方法返回null或返回一个不包含ActionMessage的ActionErrors对象,就表示表单验证成功。

5.ActionServlet根据ActionMapping实例包含的映射信息决定将请求转发给哪个Action。如果相应的Action实例不存在,就先创建这个实例,然后调用Action的execute()方法。

6.Action的execute()方法返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指向的JSP组件。

7.ActionForward对象指向的JSP组件生成动态网页,返回给客户。

订阅: 博文 (Atom)