java代码重用的一点思考

原创 2015年12月11日 17:26:47

前言:

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

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

JAVA代码重用机制复用类之继承语法(附源码)

前言        继承是所有OOP语言和Java语言不可缺少的组成部分。当创建一个类时,总是在继承,因此,除非已明确指出要从其他类中继承,否则就是在隐式地从Java的标准根类Object进...

提高Java代码可重用性的三个措施

提高Java代码可重用性的三个措施                      &...

java 复用代码(组合与继承)

java中的类都是围绕着类进行的。可以通过创建新类来复用代码,而不必从头编写。可以使用别人已经开发并调试好的类。此方法使用的窍门在于使用类而不破坏现有的程序代码。达到这一目的的方法有两种。第一种方法非...

Java中的封装和复用

封装在C语言中可以通过结构体封装多个变量,表示一个事物的多个属性。而Java是一种面向对象的编程语言,它更进一步,将变量和函数封装在一个类中,使用对象的形式模拟一个事物的多个方面,变量对应着对象中的域...

状态机的伪Java代码实现与一点想法

早些日子,一直在思考状态机是什么东西,在网上查了半天,多数内容讲的和编程并不相关。不过差了一些资料后,还是学到了一点。这篇文章就记录这件事情。状态机是把一个对象的所有状态写出来,同时实现状态变化。在不...

各种编码Unicode UTF-8 GBK 及一点Java代码

Unicode UTF-8 GBK这些不同的编码,我们可以想象为不同的字典。同一个汉字,在不同的字典里面,我们用不同的编号保存。比如汉字"陈"在Unicode里编号为9648,在GBK里面是0xB3C...

(转载)如何提高Java代码可重用性

如何提高Java代码可重用性 (转载)原文地址:http://doc.studyget.com/showdoc-52275.html 说明:本文介绍了三种修改现有代码提高其可重用性的方法,分别是:...

提高Java代码可重用性的三个措施

提高Java代码可重用性的三个措施  本文介绍了三种修改现有代码提高其可重用性的方法,它们分别是:改写类的实例方法,把参数类型改成接口,选择最简单的参数接口类型。  措施一:改...

用Groovy思考 第一章 用Groovy简化Java代码

用Groovy思考  第一章 用Groovy简化Java代码作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs1. Groovy的安装目前Groovy的最新版...
  • chszs
  • chszs
  • 2013-04-03 23:35
  • 3326
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)