**
Java程序的设计思想
**
设计思想的基本原则:
1、面向接口编程
2、优先使用对象组合而非继承
3、分层结构
4、层之间交互的基本原则
重点内容
一、 面向接口编程
接口及相关机制最基本的作用:通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。根据接口可以了解对象的交互界面,而不需要了解对象所属的类。
面向对象程序设计讲究“提高内聚,松散耦合”,那么不同的程序模块怎么相互访问呢,就是通过接口,也就是接口是各部分对外的统一外观。接口在Java程序设计中体现的思想就是封装隔离,因为接口只是描述一个统一的行为,所以开发人员在面向接口编程时并不关心具体的实现。
内聚就是指组件所有功能尽量在内部实现,所需要的功能尽量在内部都能够找到,即使是小到一个类也一样,一个方法所需要的其它方法尽量在该类内部都实现了。
耦合是指组件之间的横向联系,即一个组件要使用别的组件的功能。此时,如果别的组件修改了,那么当前组件也要进行修改。当然,我们也不可能把所有的功能都在内部实现,跟外部完全没有任何交互(除非只写一个HelloWorld)。类的设计有一个原则,就是类的功能要单一(不能把所有的功能都写在一个类中)。因此,这两者间要进行权衡。这样,一个组件在设计时肯定是要和其它组件耦合的,为了减少耦合时产生的连动影响同时又要保持内聚性,采用面向接口编程是比较合理的解决方案,接口体现的“封装隔离”的设计思想,其中的封装就是提高内聚,而隔离就是减少耦合。组件中设计时,内部实现都封装隐藏起来,对外只提供接口(如果组件修改了,只要接口没变,使用该组件的其它组件就不用修改。一方面让组件间的耦合松散了,另一方面也实现对组件内部实现的封装)。
接口本身不会增加程序的功能(因为它没有实现代码),但是采用接口可以让整个程序的体系结构更加灵活,它的作用不要体现在体系结构设计上,使用程序更容易扩展。
二、分层
① 表现层功能:展示数据、人机交互、收集参数调用逻辑层。
② 逻辑层功能:进行数据的逻辑校验、进行逻辑判断、实现业务功能、处理相关功能、处理后续流程、组织数据返回给表现层。
③ 数据层功能:实现数据持久化、实现对象和持久化数据的双向映射。
设计模式
单例
饿汉式
不管是否已经生成,先new一个:
class Single{
private static final Single s = new Single();
private Single(){
}
public static Single getInstance(){
return s;
}
}
懒汉式
先判断是否为null,没有再new
class Single2 {
private static Single2 s = null;
private Single2(){
}
public static Single2 getInstance() {//可以在此处添加synchronized,确保线程安全
if(s==null)
s=new Single2();
return s;
}
}
缓存在单例中的使用
//单例+缓存---控制池大小,每个对象的key值由该类内部指定
public class A {
//1创建一个单例的池
private static Map<Integer, A> pool = new HashMap<Integer, A>(); //池--集合: Map:key-value
//当前对象的序号
private static int num=0;
//总数量
private final static int MAX_SIZE=3;
public synchronized static A getInstance(){
//2根据num到池中去获取obj
A obj = pool.get(num);
if(obj==null){
obj = new A();
pool.put(num, obj);
}
num = (num+1)%MAX_SIZE; //范围: 0 ~ MAX_SIZE-1
//3如果该obj存在则返回,否则创建一个新的放入池中并返回
return obj;
}
}
值对象
基本的编写步骤
第1步:写一个类,实现可序列化(如果以后数据是往数据库里存的,那么可以不序列化,节省资源)
第2步:私有化所有属性,保持一个默认构造方法(public无参)
第3步:为每个属性提供get()、set()方法(如果是boolean型变量,最好把get改成is)
第4步:推荐覆盖实现equals()、hashCode()和toString()方法
值对象的本质是“封装数据”
装饰模式
在不对原有对象类进行修改的基础上,给一个或多个已有的类对象提供增强额外的功能。
以MyBufferedReader为例
版本1
/*
*增强FileReader类,使它具有如下功能:
* (1) 提供带缓冲的myRead()方法,对原有的read()方法进行增速;
(2)提供一个能够每次读取一行字符的myReadLine()方法。
*/
public class MyBufferedReader {
private char[] cbuf = new char[1024];// 缓存
private int pos = 0; // 当前读取的位置
private int count = 0;// 记录缓存中当前的字符总数
// 封装一个FileReader对象,帮助我们实现从文件中读取一批数据
private FileReader r = null;
public MyBufferedReader(FileReader r) {
super();
this.r = r;
}
/*
* 从缓存中读取一个字符数据返回
* 所读取的字符,如果到达文件末尾则返回-1
*/
public int myRead() throws IOException {
// 从文件中把数据读取到缓存buf[]中
if (count <= 0) {
// System.out.println("**********");
count = r.read(cbuf);
if (count == -1) {
return -1;
}
pos = 0;
}
char ch = cbuf[pos];
pos++;
count--;
return ch;
}
// 回车字符: \r 13
// 换行字符: \n 10
public String myReadLine() throws IOException {
StringBuilder sb = new StringBuilder();
int ch = 0;
// 有回车换行符部分
while ((ch = myRead()) != -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 close() throws IOException {
r.close();
}
}
版本2
/* 版本2: 增强InputStreamReader类,使它具有:
* (1) 提供带缓冲的myRead()方法,对原有的read()方法进行增速;
(2)提供一个能够每次读取一行字符的myReadLine()方法。
*/
public class MyBufferedReader {
private char[] cbuf= new char[1024];//缓存
private int pos=0; //当前读取的位置
private int count=0;//记录缓存中当前的字符总数
//封装一个InputStreamReader对象,帮助我们实现从文件中读取一批数据
private InputStreamReader r = null; //★1★
public MyBufferedReader(InputStreamReader r) { //★2★
super();
this.r = r;
}
/*
* 从缓存中读取一个字符数据返回
* 所读取的字符,如果到达文件末尾则返回-1
*/
public int myRead() throws IOException{
//从文件中把数据读取到缓存buf[]中
if(count<=0){
//System.out.println("**********");
count = r.read(cbuf);
if(count==-1){
return -1;
}
pos=0;
}
char ch = cbuf[pos];
pos++;
count--;
return ch;
}
//回车字符: \r 13
//换行字符: \n 10
public String myReadLine() throws IOException{
StringBuilder sb=new StringBuilder();
int ch=0;
//有回车换行符部分
while( (ch=myRead())!=-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 close() throws IOException{
r.close();
}
}
版本3
/*
* 同时增强FileReader、InputStreamReader和PipedReader类,使它具有:
* (1) 提供带缓冲的myRead()方法,对原有的read()方法进行增速;
(2)提供一个能够每次读取一行字符的myReadLine()方法。
*/
public class MyBufferedReader extends Reader { // ★3★ ---
private char[] cbuf = new char[1024];// 缓存
private int pos = 0; // 当前读取的位置
private int count = 0;// 记录缓存中当前的字符总数
// 封装一个Reader对象,帮助我们实现从文件中读取一批数据
private Reader r = null; // ★1★
public MyBufferedReader(Reader r) { // ★2★
super();
this.r = r;
}
/* 从缓存中读取一个字符数据返回
* 所读取的字符,如果到达文件末尾则返回-1
*/
public int myRead() throws IOException {
// 从文件中把数据读取到缓存buf[]中
if (count <= 0) {
// System.out.println("**********");
count = r.read(cbuf);
if (count == -1) {
return -1;
}
pos = 0;
}
char ch = cbuf[pos];
pos++;
count--;
return ch;
}
// 回车字符: \r 13
// 换行字符: \n 10
public String myReadLine() throws IOException {
StringBuilder sb = new StringBuilder();
int ch = 0;
// 有回车换行符部分
while ((ch = myRead()) != -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 close() throws IOException {
r.close();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
int num = 0;
int ch = myRead();
if (ch == -1) {
return -1;
}
for (int i = off; i < len; i++) {
num++;
cbuf[i] = (char) ch;
ch = myRead();
if (ch == -1) {
break;
}
}
return num;
}
}