如何处理接口子类的更改?

时间:2014-03-25 17:58:56

标签: java api design-patterns inheritance interface

假设一个初始场景,之后我将成为修改过的有问题的案例。

interface Logger {
    log() { } 
} 

class LogFile extends Logger {
     log()  { // log to file }
}

class LogDB extends Logger {
     log() { // insert log into DB   } 
}

现在LogDB变成了类似的东西:

class LogDB {
    logMySQL() { };
    logMongo() { };
}

如何将此更改合并到LogDB中,同时我还希望它适合Logger接口?

3 个答案:

答案 0 :(得分:2)

我认为最好制作LogDB类的两个子类 - 一个用于处理MongoDB,另一个用于MySQL。

class LogMongoDB extends LogDB {
    @Override
    log() {
       //persist the log in MongoDB
    }
}

class LogMySQL extends LogDB {
    @Override
    log() {
       //persist the log in MySQL
    }    
}

答案 1 :(得分:1)

如果LogDB需要实现Log,但还必须执行一些自定义日志记录,请根据接口的要求添加执行通用日志记录活动的函数,并从每个自定义版本调用它(反之亦然,视您的需要而定):

public void log()  {
   //Common logging stuff here
}
public void logDB()  {
   //Database-specific logging here...
   log();
}
public void logMongo()  {
   //Mongo-specific logging here...
   log();
}

但正如@kocko所说,你似乎正在将两种类型的日志记录混合到一个对象中,这就是为什么你首先要问这个问题的原因。按照他的建议拆分它,然后你就不会开始这个问题了。

答案 2 :(得分:1)

我的做法不同,不是继承,但成分

interface Logger {
    log(String message) { } 
} 

class LogFile extends Logger {
     public LogFile(File file) {}
     log(String message)  { /* log to file */ }
}

class LogDB extends Logger {
     private DBLogConf dbConf;
     private DBAbstractionLayer dbal;
     public LogDB(IDBLogConf dbConf, IDBAbstractionLayer dbal) {
         this.dbConf = dbConf;
         this.dbal = dbal;
     }
     log(String message) { 
         List<String> fields = new ArrayList<String>();
         fields.add(dbConf.getLogField());

         List<String> values = new ArrayList<String>();
         fields.add(message);

         dbal.insert(dbConf.getContainer(), fields, values);
     } 
}

interface IDBLogConf {
    public String getContainer(); // table or document
    public String getLogField();
}

class DBLogConf implements IDBLogConf { /* ... */ }

interface IDBAbstractionLayer {
    public void insert(String container, List<String> fields, List<String> values) {
        // ...
    }

    // other methods
}

class JDBCAbstractionLayer implements IDBAbstractionLayer {
    private Connection conn;
    public JDBCAbstractionLayer(Connection conn) {
        this.conn = conn;
    }

    public function insert(...) { /* ... */}
}

abstract class NoSQLAbstractionLayer implements IDBAbstractionLayer {
    // ...
}

class MongoAbstractionLayer extends NoSQLAbstractionLayer {
    // ...
}

把这一切都放在一起:

IDBConf dbConf = new DBConf('log_table', 'details');
IDBAbstractionLayer dbal = new JDBCAbstractionLayer(/* some JDBC connection, */);

Logger dbLogger = new LogDb(dbConf, dbal);
dbLogger.log("Something");

Logger fileLlogger = new LogFile(new File('/var/log/my_log'));
fileLogger.log("Something");

然而,这似乎比上述示例更复杂,此实现不违反SRP并避免代码重复。