简体   繁体   中英

How do I properly implement my Java interface with inner class?

I had a block of code that wrote events to a log file:

Date rightNow = new Date();
File logfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), ("MyLogfile" + fileSDF.format(rightNow) + ".txt"));
FileOutputStream fos;
boolean documents_directory_exists = logfile.getParentFile().exists();
boolean documents_directory_created = true;
if(!documents_directory_exists) documents_directory_created = logfile.getParentFile().mkdirs();
if(documents_directory_created){
    try {
        fos = new FileOutputStream(logfile, true);
        fos.write(new LogEntry(timestampSDF.format(rightNow), boolean01, someInt, boolean02).toString().getBytes());
        fos.close();
    } catch (IOException ioe) {
        Log.e(SomeClass.class.getName(), String.format(Locale.US, "%s %s", Constants.DEFAULT_FILE_ERROR_MESSAGE, ioe.getMessage()));
    }
} else {
        Log.e(SomeClass.class.getName(), String.format(Locale.US, "%s %s", Constants.DEFAULT_FILE_ERROR_MESSAGE, "Cannot create the necessary directories."));
}

I had this code in multiple places, so I thought I would stick it in an interface so I could make my code cleaner. So I created this interface:

public interface LogWriter {
    void writeLog(LogEntry logEntry);
}

Where LogEntry is:

public class LogEntry{
    private String timestamp;
    private boolean booean01;
    private int someInt;
    private boolean boolean02;

    public LogEntry(timestamp, boolean01, someInt, boolean02){
        this.timestamp = timestamp;
        this.boolean01= boolean01;
        this.someInt= someInt;
        this.boolean02= boolean02;
    }

    // Getters and Setters
}

I want to keep my code very clean, so I wanted to do all of the file I/O within the interface, so I created an inner class:

public interface LogWriter {
    void writeLog(LogEntry logEntry);

    class WriteMeToTheLog {
        LogEntry logEntry;

        private static final SimpleDateFormat fileSDF = new SimpleDateFormat(Constants.ACCESS_LOGFILE_NAME_FORMAT);

        public WriteMeToTheLog(LogEntry logEntry) {
            this.logEntry = logEntry;
        }

        public void write(){
             Date rightNow = new Date();
             File logfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), ("MyLogfile" + fileSDF.format(rightNow) + ".txt"));
             FileOutputStream fos;
             boolean documents_directory_exists = logfile.getParentFile().exists();
             boolean documents_directory_created = true;
             if(!documents_directory_exists) documents_directory_created = logfile.getParentFile().mkdirs();
             if(documents_directory_created){
                 try {
                     fos = new FileOutputStream(logfile, true);
                     fos.write(new LogEntry(timestampSDF.format(rightNow), boolean01, someInt, boolean02).toString().getBytes());
                     fos.close();
                 } catch (IOException ioe) {
                     Log.e(SomeClass.class.getName(), String.format(Locale.US, "%s %s", Constants.DEFAULT_FILE_ERROR_MESSAGE, ioe.getMessage()));
                }
            } else {
                Log.e(SomeClass.class.getName(), String.format(Locale.US, "%s %s", Constants.DEFAULT_FILE_ERROR_MESSAGE, "Cannot create the necessary directories."));
            }
        }
    }
}

This is where I am getting VERY lost.

In one of the classes where I had the original block of code, I implemented that new interface:

public class OneOfMyClasses extends BaseClass implements LogWriter {
    public myMethod(){
        // This is where I had the original block of code
        // WHAT DO I DO HERE NOW???
    }

    @Override
    public void writeLog(){
        Date rightNow = new Date();
        writeMeToTheLog(new LogEntry(timestampSDF.format(rightNow), boolean01, someInt, boolean02).toString().getBytes());
        writeMeToTheLog.write();
    }
}

How do I use this new functionality?

I want to keep my code very clean, so I wanted to do all of the file I/O within the interface, so I created an inner class

Declaring a class in an interface is not necessary "clean".
Besides this will not be an inner class but a static class as the class is declared in an interface.
All of these are counter intuitive. The class is an implementation and the interface is an API. It doesn't sound good that an API declares the implementation structure.

About your question, I think that WriteMeToTheLog (that contains the logging logic you extracted) has also to implement LogWriter as it looks like a LogWriter implementation.
And the client class should have a dependency to WriteMeToTheLog , probably as field set in the constructor while it can still implement LogWritter if it makes sense.

That would give :

class WriteMeToTheLog implements LogWriter { ...}

And :

public class OneOfMyClasses extends BaseClass implements LogWriter {
    private LogWriter logWriter;

    public OneOfMyClasses (LogWriter logWriter){
       this.logWriter = logWriter;
    }

    @Override
    public void writeLog(){
        Date rightNow = new Date();       
        logWriter.write();
    }
}

Now you can instantiate the client class by setting the dependency :

OneOfMyClasses o = new OneOfMyClasses(new WriteMeToTheLog(new LogEntry(timestampSDF.format(rightNow), boolean01, someInt, boolean02).toString().getBytes());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM