Предположим начальный сценарий, следуя которому я был бы модифицированным проблемным случаем.

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?

0
JavaDeveloper 25 Мар 2014 в 21:58

3 ответа

Лучший ответ

Если 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, вы, похоже, смешиваете два типа входа в один объект, поэтому вы в первую очередь задаете вопрос. Разделите его, как он предлагает, тогда у вас не будет этой проблемы с самого начала.

1
aliteralmind 25 Мар 2014 в 22:03

Я думаю, что лучше создать два подкласса класса 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
    }    
}
2
Konstantin Yovkov 25 Мар 2014 в 22:03

Я бы поступил иначе, не с наследованием , а с составом .

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 и позволяет избежать дублирования кода.

1
Henrique Barcelos 26 Мар 2014 в 00:19