java代码重用的一点思考

前言:

大量结构、功能相近的冗余的代码不仅带来了维护上的额外成本,而且更重要的是让代码变得丑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接口的子类 = 完整的类

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值