java代码重用的一点思考

来源:互联网 发布:淘宝电信旗舰店 编辑:程序博客网 时间:2024/05/25 22:15

前言:

大量结构、功能相近的冗余的代码不仅带来了维护上的额外成本,而且更重要的是让代码变得丑low。
更好的代码重用,使程序代码短小精炼才能体现手艺的价值。

java有三种基本的方式支持进行代码重用

1. Interface implements

百分百抽象的类,对于实现接口的类来说,根本无法重用,但对于依据接口标准调用的类来说可以很方便的,一次写成,到处调用。

2. extends abstract class

使用抽象方法的类,(继承抽象类)通过抽象类中的非抽象方法提供代码重用,通过其中的抽象方法为不同的子类提供灵活性

3. extends class

这恐怕不是什么正经的方法,但我经常不自然的采用。。。

最常见的情况是这样的,我打算写一个类B,然后发现它和我之前写过的类A在行为逻辑上很像,只用某几个(或某一个)关键方法不同。虽然我用的是java但我并不想就因此写一堆重复的代码(最讨厌机械重复的工作)然后我开始考虑重用之前的代码

  1. 首先,我不打算把类A修改成一个抽象类,然后A’ 、B继承这个抽象类。因为这样会增加不必要的逻辑层次,让直接的问题变得复杂(另外抽象函数无法实例化,本身也有些限制)最好是直接从A继承过来。

  2. 这时候java的同心圆式的继承使用原则(父类的方法只能使用父类的属性、调用父类的方法;)圆内的接触不到园外的,所以我发现我居然无法通过在继承的父类的方法,调用子类中覆盖的方法。再加上java奇葩的构造器强制继承(子类中没用显式定义构造器函数,或定义了,但没有显式调用父类的构造器,会自动从父类中寻找无参构造器然后调用,如果你在父类中定义了构造器,但没有定义无参版本的构造器,那恭喜你,父类中的构造器会覆盖磨人的无参构造器,编译器找不到父类的无参构造器,于是报错。。。)
    ps:这反映了java在设计之初的一些固有弊端,但我没有深入了解这个方面,关于这方面的阐述,有一本很厚、很学术、很绕的书,那本书被很多人奉为圣经,甚至有一些人对无法真正理解它的内容而感到羞愧,引发了对自己人生的严肃的拷问。。。对此我只能感慨,这些人真有时间,看看the c++ programming language 也是好的嘛,就好比都信息战时代了,还纠结着自己对滑膛枪的组装工艺不精通,有那个时间学一下枪械物理学也是好的嘛

  3. 于是我采取在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接口的子类 = 完整的类

从设计模式的角度, 可以采用带钩子的模板模式, 也就是带很多默认实现方法(钩子)的抽象类
也可以用策略模式, 关键的算法抽象成接口, 按照不同方法实现接口, 然后组合的方式使用这些类

0 0
原创粉丝点击