黑马程序员---工具类和设计模式
2013-05-23 21:06
92 查看
------- Java、.Net、Android培训期待与您交流!-------
一、工具类
需求:定义一个工具类,实现int型数组的打印、获取最值、选择排序、冒泡排序、折 半查找(二分查找)等功能。
思路:
工具类:工具类中不需要有类的特有数据(属性),仅仅用到了类中的方法,那么将方法都static化,直接通过类名调用,而且不需要建立对象,所以也把构造函数私有化,进制其他程序创建该类对象,使得代码更严谨。我们只需调用相应方法就可以达到目的。把需要对外的方法都public,扩大其权限,同时把不需要对外的成员都private,不对外公开。
步骤:
1.定义类ArrayTool工具类,且将构造函数私有化;
2.分别定义各功能函数,需要对外的方法全部public,不需要对外的成员都private。
总结:工具类的定义,方便了程序员对资源的合理利用,我们只需要知道该工具类(或工具包)有哪些功能,选择适合自己需要的功能就行,而不需要知道该功能具体是怎么实现的,因为方法都是静态的,不需要创建对象,方便又快捷。在正式的开发中就会经常用到工具类来提高程序员的工作进度。
[b]二、设计模式
java中一共有23种设计模式。
1、单例设计模式
作用:使对象唯一,用于数据共享。必定提供一个静态的对外方法来获取该单利的实例。
饿汉式:先初始化对象。类一进内存,就已经建立好了对象(单例设计常用:因为安全简单)。
懒汉式:对象是方法被调用时,才开始初始化,也叫做延时加载。类进内存,对象还没有存在,只有调用了与之对应的方法时才创建对象(面试考点:加载存在缺陷,可能会导致对象重复建立,与单例设计对象唯一相悖,开发基本不用,改进型代码体相对饿汉式麻烦)。
需求:写出单例设计模式的两种体现:分别为饿汉式和懒汉式。
思路:
单例设计模式是解决某一类问题最行之有效的方法,它解决的是某一个类中只存在一个对象,所以只需做到下面的三点即可完成设计,而其他的对于事物的描述,一切照旧。
1.将构造函数私有化,保证其不被创建对象;
2.在类中创建一个本类对象,保证其他程序可以访问到该类对象;
3.提供一个方法可以获取到该对象,方便其他程序对自定义对象的访问。
步骤:懒汉式
1.创建一个空对象;
2.创建私有化的构造函数;
3.定义一个方法体来获取该对象,且在方法体中进行判断对象是否为空,不为空则不创建对象,直接返回对象在堆内存中的地址。
4.饿汉式外加方法体:通过覆盖父类Object.equals来实现本类对象特有的比较内容。
2、模版设计模式
模版方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,
那么这时候就将不确定的部分暴露出去,有该类的子类去完成。
需求:获取一段程序运行的时间。
思路:获取程序开始和结束时间并相减即该程序的运行时间。获取时间的方法:System.currentTimeMillis()。
3、装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类成为装饰类。装饰类通常会通过构造方法接收被装饰的对象。
BufferedReader 类中特有方法 readLine 底层调用的仍然是 read 方法的,是一个字符一个字符的读取,并将暂时读取的字符存入到一个临时容器中,当读取到某一行的终止(换行 ('\n')、回车 ('\r') 或回车后直接跟着换行)时,再返回容器中的数据。也属于装饰设计模式。
装饰和继承:若多个类需要另一类的缓冲功能,以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。现在优化思想,单独描述一下缓冲内容。将需要被缓冲的对象,传递进来,也就是谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。
特点:装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类于类之间的关系。
注:装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。
示例:
解析:自定义读取行功能中,if(sb.length()!=0) 存在的理由:如果一行文本的结尾没有回车符,那么while 循环体中的 if(ch=='\n') 将读不到,所以 StringBuilder 中存入的数据没有被取出,就要在循环体外再判断一次。
总结:设计模式是根据实际经验总结出来的,是一种纯思想的思考问题的方法,深入学习必须了解设计模式,有利于自己在各开发语言学习中的发展(不论java、c++、c#都通吃),虽然它是纯思想的,但是得根据具体的项目来实施,如果没有实际的开发经验,只通理论同样不切实际。
一、工具类
需求:定义一个工具类,实现int型数组的打印、获取最值、选择排序、冒泡排序、折 半查找(二分查找)等功能。
思路:
工具类:工具类中不需要有类的特有数据(属性),仅仅用到了类中的方法,那么将方法都static化,直接通过类名调用,而且不需要建立对象,所以也把构造函数私有化,进制其他程序创建该类对象,使得代码更严谨。我们只需调用相应方法就可以达到目的。把需要对外的方法都public,扩大其权限,同时把不需要对外的成员都private,不对外公开。
步骤:
1.定义类ArrayTool工具类,且将构造函数私有化;
2.分别定义各功能函数,需要对外的方法全部public,不需要对外的成员都private。
public class ArrayTool { private ArrayTool(){} ///构造函数私有化 //获取最小值角标 public static int getMin(int[] arr) { /* int min = arr[0]; //初始化min使其等于数组arr的第一个值。 for (int i=1; i<arr.length; i++) { if (min>arr[i]) min = arr[i]; } return min; */ int min = 0; for (int i=1; i<arr.length; i++) { if (arr[min]>arr[i]) //将min作为数组的角标使用。 min = i; } return min; } //获取最大值的角标 public static int getMax(int[] arr) { int max = 0; for (int i=1; i<arr.length; i++) { if (arr[max]<arr[i]) //将max作为数组的角标使用。 max = i; } return max; } //选择排序(升序):首先确定最小值 public static void selectSort(int[] arr) { for (int i=0; i<arr.length-1; i++) { for (int j=i+1; j<arr.length; j++) { if (arr[i]>arr[j]) swap(arr,i,j); } } } //冒泡排序(降序):首先确定最小值 public static void bubbleSort(int[] arr) { for (int i=0; i<arr.length-1; i++) { for (int j=0; j<arr.length-1-i; j++)//-i:让每一次比较的元素减少,-1:避免角标越界。 { if (arr[j]<arr[j+1]) swap(arr,j,j+1); } } } //打印数组 public static void printArray(int[] arr) { System.out.print("["); for (int i=0; i<arr.length; i++) { if (i<arr.length-1) System.out.print(arr[i]+","); else System.out.println(arr[i]+"]"); } } //元素位置置换 private static void swap(int[] arr,int a,int b) { arr[a] = arr[a] + arr; arr[b] = arr[a] - arr[b]; arr[a] = arr[a] - arr[b]; } //折半查找(二分查找):必须保证该数组是有序,升序降序均可,并返回将一个数插入该数组中的位置。 public static int halfSearch(int[] arr,int key) { int start = 0, end = arr.length-1, mid; int max = getMax(arr); int min = getMin(arr); //若key值大于最大值或小于最小值,返回插入元素的位置 if (key>arr[max]) return max; else if(key<arr[min]) return min; //while循环对在数组区间内的元素进行判断 while (start<=end) { mid = (start+end)>>1; if (key>arr[mid]) { //判断数组是升序还是降序 if (arr[0]<=arr[arr.length-1]) start = mid + 1; else end = mid - 1; } else if (key<arr[mid]) { if (arr[0]>=arr[arr.length-1]) start = mid + 1; else end = mid - 1; } else return mid; } return start; //返回将一个元素插入该数组中的位置。 } }
总结:工具类的定义,方便了程序员对资源的合理利用,我们只需要知道该工具类(或工具包)有哪些功能,选择适合自己需要的功能就行,而不需要知道该功能具体是怎么实现的,因为方法都是静态的,不需要创建对象,方便又快捷。在正式的开发中就会经常用到工具类来提高程序员的工作进度。
[b]二、设计模式
java中一共有23种设计模式。
1、单例设计模式
作用:使对象唯一,用于数据共享。必定提供一个静态的对外方法来获取该单利的实例。
饿汉式:先初始化对象。类一进内存,就已经建立好了对象(单例设计常用:因为安全简单)。
懒汉式:对象是方法被调用时,才开始初始化,也叫做延时加载。类进内存,对象还没有存在,只有调用了与之对应的方法时才创建对象(面试考点:加载存在缺陷,可能会导致对象重复建立,与单例设计对象唯一相悖,开发基本不用,改进型代码体相对饿汉式麻烦)。
需求:写出单例设计模式的两种体现:分别为饿汉式和懒汉式。
思路:
单例设计模式是解决某一类问题最行之有效的方法,它解决的是某一个类中只存在一个对象,所以只需做到下面的三点即可完成设计,而其他的对于事物的描述,一切照旧。
1.将构造函数私有化,保证其不被创建对象;
2.在类中创建一个本类对象,保证其他程序可以访问到该类对象;
3.提供一个方法可以获取到该对象,方便其他程序对自定义对象的访问。
步骤:懒汉式
1.创建一个空对象;
2.创建私有化的构造函数;
3.定义一个方法体来获取该对象,且在方法体中进行判断对象是否为空,不为空则不创建对象,直接返回对象在堆内存中的地址。
4.饿汉式外加方法体:通过覆盖父类Object.equals来实现本类对象特有的比较内容。
//饿汉式: class SingleE { private int num; //私有化的成员变量,描述照旧 //饿汉式代码体现块 private static SingleE s = new SingleE(); private SingleE(){} public static SingleE getInstance() { return s; } //方法体,描述照旧 public void setNum(int num) { this.num = num; } public int getNum() { return num; } //java中任何类都是Object的直接或间接子类,所以可以直接复写(重写、覆盖)Object父类中的equals方法, //来定义属于自己的比较内容。其中参数类型是Object表示可以传入任何类类型值。 public boolean equals(Object obj) { //判断传入值类型是否是SingleE类类型,若不是返回false。不同类型对象不能参与比较。作用:增强程序健壮性。 if (!(obj instanceof SingleE)) return false; SingleE e = (SingleE)obj; //多态:向下转型(类型符合) return this.num == e.num; } } class Person { int num; Person(int num) { this.num = num; } } class SingleDemo { public static void main(String[] args) { SingleL l = SingleL.getInstance(); SingleE s1 = SingleE.getInstance(); //创建对像s1 SingleE s2 = SingleE.getInstance(); //创建对象s2,和s1指向的堆内存地址相同,即指向对象唯一,单例设计成功。 Person p = new Person(8); //创建Person类型变量p指向new Person()在堆内存中的首地址。 //System.out.println(p); //输出的是Person类类型变量所指向的地址:Person@14a55f2 s1.setNum(8); //给s1所指对象赋值,结果为:num=8. //System.out.println("num="+s1.getNum()); s2.setNum(11); //给s2所指对象即s1所指对象传赋值,结果为:num=11,覆盖了原来的num=8.所以下面两条的输出语句都是8 //System.out.println("num="+s1.getNum()); //System.out.println("num="+s2.getNum()); System.out.println("compare end:"+s1.equals(p)); } } //懒汉式:代码体现块 class SingleL { private static SingleL s = null; //创建空对象 private SingleL(){} //私有化构造函数 public static SingleL getInstance() //定义方法体获取对象 { if(s == null) //这个if语句执行可能会出现进程挂载的情况 { //s = new Single(); //为了防止多个进程挂载后出现对象重复建立的情况,采用synchronized同步代码块保证一次只有一个程序 //进入判断体。若该if语句中有一个程序挂载,那么就锁住该同步代码块语句防止其他调用程序进入该代码块。 synchronized(SingleL.class) //同步代码块 { if(s==null) s = new SingleL(); } } return s; } }
2、模版设计模式
模版方法设计模式:在定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而确定的部分在使用不确定的部分,
那么这时候就将不确定的部分暴露出去,有该类的子类去完成。
需求:获取一段程序运行的时间。
思路:获取程序开始和结束时间并相减即该程序的运行时间。获取时间的方法:System.currentTimeMillis()。
abstract class GetTime //抽象类 { /* final:最终 1、可以修饰类、函数和变量; 2、被final修饰的类不可以被继承(意为最终类); 3、被final修饰的方法不可以被子类复写; 4、被final修饰的变量(成员变量和局部变量)是一个常量只能赋值一次,且常量名所有字母均必须大写,如:PI、MY_BIRTHDAY; 5、内部类定义在类中的局部位置上,只能访问该局部被final修饰的局部变量(后期涉及)。 */ //固定方法调用未知方法(模版设计模式) public final void getTime() { long start = System.currentTimeMillis(); //获取程序开始执行的时间 runcode(); //未知方法 long end = System.currentTimeMillis(); //获取程序执行完后的时间 System.out.println("毫秒:"+(end-start)); //打印程序运行的时间 } //抽象型函数,没有方法体(不可以实例化),抽象的出现就是为了让子类复写。因为抽象类函数定义的是一个总体的方法, //但是不确定具体的执行内容,会有多种方式来实现,所以不具备方法体和参数列表。 //abstract不能和final、static、private关键字共存,共存后都不能被子类复写,抽象就没有意义了。 public abstract void runcode(); } //子类继承父类,那么子类就具有父类中所有的非私有化成员。 class SubTime extends GetTime { public void runcode() { for (int i=0; i<2222; i++) { System.out.print("*"); } } } class Template { public static void main(String[] args) { //GetTime gt = new SubTime(); //多态:向上转型:父类型引用指向子类对象。 SubTime gt = new SubTime(); gt.getTime(); } }
3、装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类成为装饰类。装饰类通常会通过构造方法接收被装饰的对象。
BufferedReader 类中特有方法 readLine 底层调用的仍然是 read 方法的,是一个字符一个字符的读取,并将暂时读取的字符存入到一个临时容器中,当读取到某一行的终止(换行 ('\n')、回车 ('\r') 或回车后直接跟着换行)时,再返回容器中的数据。也属于装饰设计模式。
装饰和继承:若多个类需要另一类的缓冲功能,以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。现在优化思想,单独描述一下缓冲内容。将需要被缓冲的对象,传递进来,也就是谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。
特点:装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类于类之间的关系。
注:装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。
示例:
class MyLineNumberReader{ private BufferedReader bufr; private int lineNumber; //定义行变量,可以通过设置行显示的起始位置。 MyLineNumberReader(BufferedReader bufr) { this.bufr = bufr; } //装饰设计模式 public String myReadLine() throws IOException { lineNumber++; return bufr.ReadLine(); //指向BufferedReader ,调用其方法 /* // 自定义读取一行的功能 StringBuilder sb = new StringBuilder(); int ch = 0; while ((ch=r.read())!=-1){ if (ch=='\r') //满足条件,跳出当前循环,进入下一次循环 continue; if (ch=='\n') //独到换行符,就返回字符串容器的中的内容 return sb.toString(); sb.append((char)ch); //向容器中添加读取到的字符 } if (sb.length()!=0) return sb.toString(); return null; */ } public void setLineNumber(int lineNumber){ this.lineNumber = lineNumber; } public int getLineNumber(){ return lineNumber; } @Test public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("Demo.java"); MyLineNumberReader mylnr = new MyLineNumberReader(fr); String line = null; mylnr.setLineNumber(50); while ((line=mylnr.myReadLine())!=null) System.out.println(mylnr.getLineNumber()+":"+line); } }
解析:自定义读取行功能中,if(sb.length()!=0) 存在的理由:如果一行文本的结尾没有回车符,那么while 循环体中的 if(ch=='\n') 将读不到,所以 StringBuilder 中存入的数据没有被取出,就要在循环体外再判断一次。
总结:设计模式是根据实际经验总结出来的,是一种纯思想的思考问题的方法,深入学习必须了解设计模式,有利于自己在各开发语言学习中的发展(不论java、c++、c#都通吃),虽然它是纯思想的,但是得根据具体的项目来实施,如果没有实际的开发经验,只通理论同样不切实际。
相关文章推荐
- 黑马程序员——Java基础——数组工具类、设计模式和继承(一)
- 黑马程序员----面向对象2(主函数、工具类、文档注释、单例设计模式)
- 黑马程序员——面向对象(数组工具类+单例设计模式)-第16天
- 黑马程序员_源自梦想 静态、工具类、单例设计模式
- 黑马程序员_ java高新之自动装箱与拆箱(引入设计模式:享元模式)
- 黑马程序员 第15天 单例设计模式
- 黑马程序员 OC中的单例设计模式
- 黑马程序员java学习第六天,static静态的使用及单例设计模式
- 黑马程序员——设计模式+正则表达式
- 黑马程序员---单列设计模式
- 黑马程序员——模板设计模式
- 黑马程序员_设计模式学习(学习积累中,未完待续)
- 黑马程序员--Java设计模式学习(一)
- 黑马程序员——Java基础——单例设计模式及扩展
- 黑马程序员_Java设计模式之单例设计模式
- 黑马程序员_Java高新技术_基本类型数据的自动拆装箱及享元设计模式
- 黑马程序员_单例设计模式
- 黑马程序员——Java基础——单例设计模式
- 黑马程序员:java基础——单例设计模式,synchronized及面试常考内容
- <<单例设计模式>>--黑马程序员