**
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;
}
}