命令行參數(shù)項目
看完老師寫的,我發(fā)現(xiàn)我的代碼真的還是弱爆了。多說無益腕扶,下面我吸取了一些經(jīng)驗,來記錄一下吨掌。
一.缺點
1.無架構(gòu)意識
目前來說半抱,我自己寫的時候都是想起什么寫什么,根本沒有架構(gòu)的意識膜宋。所謂架構(gòu)意識窿侈,通俗一點就是:
自己先畫一個圖,把程序的結(jié)構(gòu)理清楚史简。再去一個一個地填充。
實現(xiàn)命令行工具UML.png
上圖是老師對這個程序的架構(gòu)枢贿。
2.基本沒有用接口的意識
①其實可以用接口先規(guī)定一個框架萨咕,也就是都有什么方法聪建,具體實現(xiàn)的話,再創(chuàng)建一個實現(xiàn)類來實現(xiàn)即可挥下。但是我在寫的時候根本沒有這個意識现斋。
②除了規(guī)定框架迷雪,接口還可以保存各種各樣的常量倦西,別忘了接口默認(rèn)是被public static final修飾的。
③在寫實現(xiàn)類時,可以先提供一個方法的空殼,而不是說寫出一個方法倡缠,就必須要把它的所有執(zhí)行內(nèi)容寫出來载荔。
3.想的情況不全面丘损,寫的代碼不高級
①所謂“想的情況不全面”:
就是有些情況我根本沒有想到肢娘。比如輸入ls沙廉,之后緊跟著要判斷一下總的參數(shù)的個數(shù),如果是1,那就對了垢夹,因為ls就是1個參數(shù)而晒,如果你輸入 ls 然后又手誤,又連帶了一個a,那么這個時候就應(yīng)該提示一下,輸入?yún)?shù)有誤,請重新輸入俏拱。這只是一個簡單的例子。
②所謂“寫的代碼不高級”:
一個是使用的類不靈活吼句,比如我可能只會想到用String,但是可能用StringBuilder更方便一些况毅,也更高級一些尔许,但是我想不起來用這個柠新。還有一個是代碼結(jié)構(gòu)不高級,所謂高級净蚤,并不是說結(jié)構(gòu)亂套難懂钥组,而是應(yīng)該盡可能減少代碼之間的關(guān)聯(lián)度,使用一些操作使程序效率更高等等橘荠。比如老師用到了數(shù)據(jù)回調(diào)(后面還會講)作烟,但是我數(shù)據(jù)回調(diào)還沒有完全理解,今天花了半個小時查閱了很多資料才大概懂了砾医。所以最后還要復(fù)習(xí)一下自己所有的Java博客,復(fù)習(xí)一下基礎(chǔ)知識衣厘。
4.掌握的類的方法太少
有些類的方法是很常見也很實用的如蚜,但是我就是想不起來用,可能還是寫的代碼太少影暴。比如Arrays.asList()可以把Array類型轉(zhuǎn)換為List類型错邦,StringBuilder可以在后面追加字符串,也可以刪除字符串型宙,還可以找到指定字符串的索引值等等撬呢,這些方法,我都沒有掌握妆兑。
5.無自定義異常類的意識
之所以沒這個意識魂拦,我認(rèn)為還是操作不熟練毛仪。比如自定義異常類要進(jìn)行一系列拋出并捕獲,還要super(s)芯勘,這些雖然學(xué)過箱靴,但是我基本沒用過,所以很快就忘了荷愕。
二.具體代碼
①ICmd接口
用來保存常量
package interfaces;
//定義指令
public interface ICmd {
//接口里面的變量默認(rèn)被public static final修飾
String LS = "ls"; //列出當(dāng)前目錄的所有內(nèi)容
String MKDIR = "mkdir"; //創(chuàng)建目錄
String COPY = "copy"; //拷貝
String RM = "rm"; //刪除
String CD = "cd"; //進(jìn)入一個目錄
String CDP = "cd.."; //進(jìn)入上一層目錄
String[] COMMONDS = new String[] {LS,MKDIR,COPY,RM,CD,CDP};
}
②ICommond接口
用來定義方法框架
package interfaces;
//規(guī)劃一下執(zhí)行的操作
public interface ICommond {
//默認(rèn) public abstract修飾
boolean list(); //列出當(dāng)前目錄的所有內(nèi)容 名字+size
boolean mkdir(String path); //創(chuàng)建一個目錄
boolean copy(String src,String des); //將src的文件復(fù)制到des位置
boolean remove(String path); //刪除文件
boolean cd_to_child(String path); //切換當(dāng)前目錄到子目錄/進(jìn)入子目錄
boolean cd_to_parent(); //切換當(dāng)前目錄到上一層目錄
}
③MyClass類
程序入口
package Main;
import Tool.CommondTool;
public class MyClass {
public static void main(String[] args) {
CommondTool tool = new CommondTool();
tool.start();
}
}
④CommondOperation類
用來執(zhí)行某些外包操作與回調(diào)
package Tool;
import java.util.*;
import interfaces.*;
//接收用戶輸入和解析輸入類型
public class CommondOperation {
//回調(diào)對象
private ICommond listener;
//保存所有指令
private List<String> commonds;
//獲取輸入信息
private Scanner mScanner;
public CommondOperation() {
mScanner = new Scanner(System.in);
//將普通的Array類型轉(zhuǎn)化為List
commonds = Arrays.asList(ICmd.COMMONDS);
}
//接收用戶輸入的指令
public void readCommond(ICommond listener)throws PXDException.CommondNotExistException,PXDException.CommondArgumentErrorException {
this.listener = listener;
//接收指令
String commond = mScanner.nextLine();//記住這里用nextLine()
//解析指令
parseCommond(commond);
}
//解析指令
public void parseCommond(String commond)throws PXDException.CommondNotExistException,PXDException.CommondArgumentErrorException {
//將指令以空格為分割符 分開
String[] componts = commond.split(" ");//這也是當(dāng)時焦頭爛額的地方
//獲取用戶指令
String cmd = componts[0];
//判斷指令是否存在
if(!commonds.contains(cmd)) {
//輸入指令不存在
//需要拋出異常
throw new PXDException.CommondNotExistException("指令不存在");
}
//存在就解析是哪種指令
switch(cmd) {
case ICmd.CD:
//進(jìn)入某一個子目錄
if(componts.length != 2) {
//參數(shù)不正確衡怀,應(yīng)該只有兩個
throw new PXDException.CommondArgumentErrorException("cd 參數(shù)不正確");
}
listener.cd_to_child(componts[1]);
break;
case ICmd.CDP:
//進(jìn)入父目錄
if(componts.length != 1) {
//參數(shù)不正確,應(yīng)該只有兩個
throw new PXDException.CommondArgumentErrorException("cd.. 參數(shù)不正確安疗,它不需要參數(shù)");
}
listener.cd_to_parent();
break;
case ICmd.MKDIR:
//創(chuàng)建目錄
if(componts.length != 2) {
//參數(shù)不正確
throw new PXDException.CommondArgumentErrorException("mkdir 參數(shù)不正確");
}
listener.mkdir(componts[1]);
break;
case ICmd.RM:
//刪除
if(componts.length != 2) {
//參數(shù)不正確
throw new PXDException.CommondArgumentErrorException("rm 參數(shù)不正確");
}
listener.remove(componts[1]);
break;
case ICmd.LS:
//列
if(componts.length != 1) {
//參數(shù)不正確
throw new PXDException.CommondArgumentErrorException("ls不需要參數(shù)");
}
listener.list();
break;
case ICmd.COPY:
if(componts.length != 3) {
//參數(shù)不正確
throw new PXDException.CommondArgumentErrorException("copy參數(shù)不正確");
}
listener.copy(componts[1], componts[2]);
break;
}
}
}
⑤CommondTool類
繼承框架接口抛杨,并執(zhí)行具體操作
package Tool;
import java.io.File;
import Tool.PXDException.CommondNotExistException;
import interfaces.*;
//接收用戶的指令 和 處理指令
public class CommondTool implements ICommond{
//默認(rèn)啟動起來操作的目錄
private static final String DESKTOP_PATH = "C:\\Users\\劉金豪\\Desktop";//桌面
//記錄當(dāng)前操作的目錄路徑
private StringBuilder currentDirPath;
//構(gòu)造方法
public CommondTool() {
currentDirPath = new StringBuilder(DESKTOP_PATH);
}
//啟動命令行工具
public void start() {
//創(chuàng)建讀取指令的類的對象
CommondOperation operation = new CommondOperation();
//歡迎界面
System.out.println("歡迎用戶使用命令行工具!荐类!");
while(true) {
//顯示當(dāng)前路徑(只需要提示當(dāng)前路徑的最后部分)
showParent();
//輸入指令
try {
operation.readCommond(this);
} catch (Exception e) {
System.out.println(e.getMessage());//熟悉一下getMessage方法的使用
}
}
}
private void showParent() {
//獲取最后一個\\的index
int start = currentDirPath.lastIndexOf("\\");
//獲取最后的內(nèi)容
String parent = currentDirPath.substring(start);//獲取子字符串
//輸出提示內(nèi)容
System.out.print(parent+"#");
}
@Override
public boolean list() {
File[]files = FileManager.getInstance().list(currentDirPath.toString());//注意轉(zhuǎn)化成字符串類型
for(File file:files) {
//獲取文件名
String name = file.getName();
//獲取文件長度
long size = file.length();
long kb = size/1024;
long by = size%1024;
System.out.print(name +" " );
for(int i = 0;i < 40 - name.length();i++) {
System.out.print(" ");
}
System.out.println(kb + "." + by + "kb");
}
return false;
}
@Override
public boolean mkdir(String path) {
//拼接完整路徑
String dirPath = currentDirPath.toString() + "\\" + path;
FileManager.getInstance().mkdir(dirPath);
return false;
}
@Override
public boolean copy(String src, String des) {
//拼接完整路徑
String srcPath = currentDirPath.toString() + "\\" + src;
String desPath = currentDirPath.toString() + "\\" + des;
FileManager.getInstance().copy(srcPath, desPath);
return false;
}
@Override
public boolean remove(String path) {
//拼接完整路徑
String dirPath = currentDirPath.toString() + "\\" + path;
FileManager.getInstance().remove(dirPath);
return false;
}
@Override
public boolean cd_to_child(String path) {
currentDirPath.append("\\" + path);
System.out.println("進(jìn)入子目錄:"+path);
return false;
}
@Override
public boolean cd_to_parent() {
//先轉(zhuǎn)換成字符串
int start = currentDirPath.toString().lastIndexOf("\\");
int end = currentDirPath.length();//復(fù)習(xí)一下怖现,這個end到底刪不刪除
currentDirPath.delete(start, end);
return false;
}
}
⑥FileManager類
用來執(zhí)行更具體的操作,因為此程序基本所有操作都是涉及文件的掉冶,所以專門用一個類來封裝操作真竖。
package Tool;
import java.io.*;
public class FileManager {
//單例模式
private static FileManager manager;
private FileManager() {
}
public static FileManager getInstance() {
if(manager == null) {
synchronized(FileManager.class) {
if(manager == null) {
manager = new FileManager();
}
}
}
return manager;
}
//創(chuàng)建目錄
public boolean mkdir(String path) {
File file = new File(path);
if(file.exists()) {
return false;
}
return file.mkdir();//mkdir返回值就是boolean類型
//mkdir要求路徑中的目錄都存在
//mkdirs如果路徑中的目錄不存在,也會自動創(chuàng)建
}
//刪除文件或目錄
public boolean remove(String path) {
File file = new File(path);
if(!file.exists()) {
return false;
}
return file.delete();
}
//列出所有文件信息
public File[] list(String path){
File file = new File(path);
if(!file.exists()) {
return null;
}
return file.listFiles(new FilenameFilter() {
//名字是點開頭的都是隱藏文件厌小,這些文件我不想要恢共。就篩選一下
public boolean accept(File file, String s) {
if(s.startsWith(".")) {
return false;
}
return true;
}
});
}
//文件或者目錄的拷貝
public boolean copy(String src,String des) {
File srcFile = new File(src);
File desFile = new File(des);
//判斷文件是否存在
if(!srcFile.exists() || desFile.exists()) {//注意這里的細(xì)節(jié)
return false;
}
//如果是文件
if(srcFile.isFile()) {
//直接拷貝文件
copyFile(src,des);
}else {
//是目錄
//創(chuàng)建當(dāng)前的目錄
desFile.mkdir();
//需要將源目錄的所有內(nèi)容拷貝到des目錄
for(File file:srcFile.listFiles()) {
copy(file.getAbsolutePath(),des + "\\" + file.getName());//注意這里是一個高級的地方,用到了嵌套
//因為目錄里面可能還有目錄璧亚。
}
}
return true;
}
private void copyFile(String src,String des) {
try (FileInputStream fis = new FileInputStream(src);
BufferedInputStream bis = new BufferedInputStream(fis);
//創(chuàng)建輸出流
FileOutputStream fos = new FileOutputStream(des);
BufferedOutputStream bos = new BufferedOutputStream(fos);){
//創(chuàng)建buffer
byte[] buffer = new byte[1024];
int len = 0;
while((len = bis.read()) != -1) {
bos.write(buffer);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}
//也可以使用finally關(guān)閉讨韭,那么先關(guān)閉后面創(chuàng)建的,再關(guān)閉前面創(chuàng)建的
}
}
⑦PXDException類
自定義異常類
package Tool;
//自定義異常
public class PXDException {
//指令不存在
static class CommondNotExistException extends Exception{
public CommondNotExistException(String s) {
super(s);
}
}
//參數(shù)不正確
static class CommondArgumentErrorException extends Exception{
public CommondArgumentErrorException(String s) {
super(s);
}
}
}
三.知識漏洞
1.自定義異常類使用不熟練
具體講解在:http://www.reibang.com/p/818ea803a092
主要是注意拋出和捕獲癣蟋,以及super()方法的使用透硝。
2.回調(diào)機(jī)制沒理解
關(guān)于回調(diào)機(jī)制,網(wǎng)上有一篇非常形象的文章:https://www.cnblogs.com/heshuchao/p/5376298.html
就是A繼承了接口I疯搅,然后A調(diào)用B類的一個方法濒生,把自己這個對象this傳過去,然后B類用I類型接收幔欧,再用I點的方式罪治,回調(diào)A的方法(因為A實現(xiàn)了I,調(diào)用I的那個方法礁蔗,就是調(diào)用A的相應(yīng)方法)觉义,并把執(zhí)行結(jié)果作為參數(shù)傳遞給A的那個方法,這就是我現(xiàn)在理解的數(shù)據(jù)回調(diào)浴井。
我也是查了好久晒骇,才懂了個大概,我盡量去理解,不過也可能礙于現(xiàn)在寫的代碼太少洪囤,可能理解深還是說不上徒坡。
3.文件篩選函數(shù)不會使用
具體講解在:http://www.reibang.com/p/ceb25797c109
主要是要new FilenameFilte這個r接口,并實現(xiàn)相應(yīng)方法箍鼓,這一步操作我不熟悉
4.字符串類型方法沒掌握
當(dāng)時講課的時候介紹了大量的方法崭参,還是沒有完全掌握。比如StringBuilder如何轉(zhuǎn)換為String類型啊款咖,或者是在StringBuilder類型后面追加字符串呀何暮,怎么樣獲取索引值等等等等,如何把普通數(shù)組類型轉(zhuǎn)換為List類型等等(當(dāng)然這個不屬于字符串)
四.總結(jié)
雖然看到自己還有非常多的不足铐殃,但是發(fā)現(xiàn)的不足多海洼,進(jìn)步才能多嘛!畢竟現(xiàn)在寫的項目還是太少富腊。我要吸取這次的經(jīng)驗坏逢,爭取下一次項目都不再犯同樣失誤。加油吧W副弧J钦!