前言:
大量结构、功能相近的冗余的代码不仅带来了维护上的额外成本,而且更重要的是让代码变得丑low。
更好的代码重用,使程序代码短小精炼才能体现手艺的价值。
java有三种基本的方式支持进行代码重用
1. Interface implements
百分百抽象的类,对于实现接口的类来说,根本无法重用,但对于依据接口标准调用的类来说可以很方便的,一次写成,到处调用。
2. extends abstract class
使用抽象方法的类,(继承抽象类)通过抽象类中的非抽象方法提供代码重用,通过其中的抽象方法为不同的子类提供灵活性
3. extends class
这恐怕不是什么正经的方法,但我经常不自然的采用。。。
最常见的情况是这样的,我打算写一个类B,然后发现它和我之前写过的类A在行为逻辑上很像,只用某几个(或某一个)关键方法不同。虽然我用的是java但我并不想就因此写一堆重复的代码(最讨厌机械重复的工作)然后我开始考虑重用之前的代码
首先,我不打算把类A修改成一个抽象类,然后A’ 、B继承这个抽象类。因为这样会增加不必要的逻辑层次,让直接的问题变得复杂(另外抽象函数无法实例化,本身也有些限制)最好是直接从A继承过来。
这时候java的同心圆式的继承使用原则(父类的方法只能使用父类的属性、调用父类的方法;)圆内的接触不到园外的,所以我发现我居然无法通过在继承的父类的方法,调用子类中覆盖的方法。再加上java奇葩的构造器强制继承(子类中没用显式定义构造器函数,或定义了,但没有显式调用父类的构造器,会自动从父类中寻找无参构造器然后调用,如果你在父类中定义了构造器,但没有定义无参版本的构造器,那恭喜你,父类中的构造器会覆盖磨人的无参构造器,编译器找不到父类的无参构造器,于是报错。。。)
ps:这反映了java在设计之初的一些固有弊端,但我没有深入了解这个方面,关于这方面的阐述,有一本很厚、很学术、很绕的书,那本书被很多人奉为圣经,甚至有一些人对无法真正理解它的内容而感到羞愧,引发了对自己人生的严肃的拷问。。。对此我只能感慨,这些人真有时间,看看the c++ programming language 也是好的嘛,就好比都信息战时代了,还纠结着自己对滑膛枪的组装工艺不精通,有那个时间学一下枪械物理学也是好的嘛于是我采取在A中定义空的无参数的构造函数,然后在B中的构造函数里复制了一遍A的构造函数,(并且复制了一遍main方法)这时就可以在构造器中调用子类自己的方法。(注意,父类的方法、属性要想被同一个包内的子类继承,权限限制至少不是private)
实例class A
/**
*test on jdk1.8
*depend on null
*/
import java.io.File;
import java.util.LinkedList;
class NotDirectoryException extends Exception{
public NotDirectoryException(){
super();
}
}
/*
*with reguex support filename search
*/
public class fileSearch {
String dirname;
String filename;
File file;
LinkedList<File> filelist;
public fileSearch(String name_dir,String name_file)throws NotDirectoryException{
dirname=name_dir;
filename=name_file;
filelist=new LinkedList<File>();
file= new File(dirname);
if(!file.isDirectory()){
throw new NotDirectoryException();
}
search(file);
}
/*only for solve the damned preference of java's inheritance */
fileSearch(){
;
}
void search(File childfile){
File[] children=childfile.listFiles();
for (File child : children){
//System.out.println(child.getName());
if(child.isDirectory()){
search(child);
}
else if(child.getName().matches(filename)){
//"(.*).java","(*.).txt" etc
filelist.push(child);
}
}
}
public LinkedList<String> getmatchedFileNames(){
LinkedList<String> fnlist=new LinkedList<String>();
for (File child : filelist){
String relativepath=child.getPath().substring(dirname.length());
fnlist.push(relativepath);
}
return fnlist;
}
public LinkedList<File> getmatchedFiles(){
return filelist;
}
public void print(){
LinkedList<String> fnlist=getmatchedFileNames();
for(String child : fnlist){
System.out.println(child);
}
}
public String getDirname(){
return dirname;
}
public static void main(String[] args)throws NotDirectoryException{
fileSearch search;
Logger lg;
if(args.length<1){
System.out.println("at least one parameter");
}
else if(args.length<2){
search=new fileSearch(".",args[0]);
lg=new Logger();
lg.write(search.getmatchedFileNames());
lg.close();
search.print();
}
else{
search=new fileSearch(args[0],args[1]);
lg=new Logger();
lg.write(search.getmatchedFileNames());
lg.close();
search.print();
}
}
}
辅助类C(将搜索结果写到文件中)
import java.io.File;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
/*
*construct a log to save message
*/
public class Logger{
File file;
BufferedWriter writer;
String filename;
Logger(){
try{
filename=new String("tmp.log");
file=new File(filename);
writer=new BufferedWriter(new FileWriter(file,true));
}
catch(IOException ex){
ex.printStackTrace();
}
}
Logger(String fn){
try{
filename=fn;
file=new File(filename);
writer=new BufferedWriter(new FileWriter(file,true));
}
catch(IOException ex){
ex.printStackTrace();
}
}
void write(String in){
try{
writer.write(in);
}
catch(IOException ex){
ex.printStackTrace();
}
}
void write(LinkedList<String> ins){
for(String in : ins){
write(in+"\n");
}
}
void flush(){
try{
writer.flush();
}
catch(IOException ex){
ex.printStackTrace();
}
}
void close(){
try{
writer.close();
}
catch(IOException ex){
ex.printStackTrace();
}
}
}
直接从类A继承的类B(从并发地目录中搜索文件)
/**
*test on jdk1.8
*depend on fileSearch.java
*/
import java.util.LinkedList;
import java.io.File;
public class fileConcurrenceSearch extends fileSearch {
int threadnum=3;
public fileConcurrenceSearch(String name_dir,String name_file)throws NotDirectoryException{
dirname=name_dir;
filename=name_file;
filelist=new LinkedList<File>();
file= new File(dirname);
if(!file.isDirectory()){
throw new NotDirectoryException();
}
search(file);
}
class ConcurrenceSearch implements Runnable{
LinkedList<File> children;
ConcurrenceSearch(LinkedList<File> ls){
children=ls;
}
public void run(){
try{
go();
}
catch (NotDirectoryException ex){
ex=new NotDirectoryException();
ex.printStackTrace();
}
}
void go()throws NotDirectoryException{
for(File child : children){
LinkedList<File> childlist=new fileSearch(child.getPath(),filename).getmatchedFiles();
synchronized(this){
filelist.addAll(childlist);
}
childlist=null;
}
}
}
/*overload the parent's method*/
void search(File childfile){
LinkedList<File> dirlist=new LinkedList<File>();
/*search in the first level directory*/
File[] children=childfile.listFiles();
for (File child : children){
//System.out.println(child.getName());
if(child.isDirectory()){
dirlist.push(child);
}
else if(child.getName().matches(filename)){
//"(.*).java","(*.).txt" etc
filelist.push(child);
}
}
int size=dirlist.size();
int ave=size/threadnum;
if(ave==0){
if(size==0){
return;
}
else if(size==1){
File e=dirlist.pop();
dirlist=null;
search(e);
}
else{
//Thread first,second;
LinkedList<File>children1=new LinkedList<File>();
for(int i=0;i<(size/2);++i){
children1.push(dirlist.pop());
}
new Thread(new ConcurrenceSearch(dirlist)).start();
new Thread(new ConcurrenceSearch(children1)).start();
}
}
else{
for(int i=0;i<threadnum-1;++i){
LinkedList<File>subchildren=new LinkedList<File>();
for(int j=0;j<ave;++j){
subchildren.push(dirlist.pop());
}
new Thread(new ConcurrenceSearch(subchildren)).start();
}
new Thread(new ConcurrenceSearch(dirlist)).start();
}
}
public static void main(String[] args)throws NotDirectoryException{
fileConcurrenceSearch search;
Logger lg;
if(args.length<1){
System.out.println("at least one parameter");
}
else if(args.length<2){
search=new fileConcurrenceSearch(".",args[0]);
lg=new Logger();
lg.write(search.getmatchedFileNames());
lg.close();
search.print();
}
else{
search=new fileConcurrenceSearch(args[0],args[1]);
lg=new Logger();
lg.write(search.getmatchedFileNames());
lg.close();
search.print();
}
}
}
2016.6.11续编
从某种角度来看,造成这种尴尬的原因是Java的类或者Java的接口都不是完整的类,
只有Java接口 + 实现这个Java接口的子类 = 完整的类
从设计模式的角度, 可以采用带钩子的模板模式, 也就是带很多默认实现方法(钩子)的抽象类
也可以用策略模式, 关键的算法抽象成接口, 按照不同方法实现接口, 然后组合的方式使用这些类