Поддерживает ли ColdFusion делегатов? - PullRequest
3 голосов
/ 06 сентября 2011

У меня есть несколько методов доступа к базе данных, которые заключены в блок try / catch:

function GetAll() {
    try {
        entityLoad("Book");
    }
    catch (any e) {
        throw (type="CustomException", message="Error accessing database, could not read");
    }
}

function Save(Book book) {
    try {
        entitySave(book);
    }
    catch (any e) {
        throw (type="CustomException", message="Error accessing database, could not save);
    }
}

Как видите, блок try / catch повторяется несколько раз, где единственное, что меняется, - это сообщение. Можно ли создать делегата в ColdFusion, чтобы я мог вместо этого сделать что-то подобное (используя лямбду C # для представления анонимного делегата)?:

function GetAll() {
    DatabaseOperation(() => entityLoad("Book"), "could not read");
}

function Save(Book book) {
    DatabaseOperation(() => entitySave(book), "could not save");
}

function DatabaseOperation(delegate action, string error) {
    try {
        action.invoke();
    }
    catch (any e) {
        var message = "Error accessing database, " & error;
        throw (type="CustomException", message=message);
    }
}

1 Ответ

6 голосов
/ 06 сентября 2011

На основе вашего примера, а не с CF9.

В CF10 идут закрытия, которые, вероятно, позволят вам сделать что-то вроде:

function GetAll() {
    DatabaseOperation( closure(){ entityLoad("Book") } , "could not read");
}

function Save(Book book) {
    DatabaseOperation( closure(){ entitySave(book) } , "could not save");
}

function DatabaseOperation(closure action, string error) {
    try {
        action();
    }
    catch (any e) {
        var message = "Error accessing database, " & error;
        throw (type="CustomException", message=message);
    }
}

(синтаксис может отличаться, непомните, если это было именно так)

В качестве альтернативы, вы могли бы использовать evaluate здесь, я думаю ...

function GetAll() {
    DatabaseOperation( 'entityLoad("Book")' , "could not read");
}

function Save(Book book) {
    DatabaseOperation( 'entitySave(book)' , "could not save");
}

function DatabaseOperation(string action, string error) {
    try {
        evaluate(action);
    }
    catch (any e) {
        var message = "Error accessing database, " & error;
        throw (type="CustomException", message=message);
    }
}

Лично я бы просто удалил try / catch и использовал onError в Application.cfc - кажется, бесполезно маскировать исходную ошибку и вместо этого выдавать более общую ошибку?

Обновление: еще две возможные альтернативы ...

Другой вариант, который в настоящее время работает, - это иметь функцию-обертку public, которая вызывает функцию DatabaseOperation, передавая имя частной функции, которая выполняетфактическая логика, как это:

function GetAll() {
    DatabaseOperation( real_GetAll , Arguments , "could not read");
}
private function real_GetAll() {
    entityLoad("Book")
}

function Save(Book book) {
    DatabaseOperation( real_Save , Arguments , "could not save");
}
private function real_Save(Book book) {
    entitySave(book)
}

function DatabaseOperation(any action, struct args , string error) {
    try {
        action( argumentcollection=args )
    }
    catch (any e) {
        var message = "Error accessing database, " & error;
        throw (type="CustomException", message=message);
    }
}

Если вам не нравится идея определения функций дважды, но вы не против скрыть API, вы можете установить методы как private, а затем использовать onMissingMethod:

private function GetAll()
{
    entityLoad("Book")
}

private function Save(Book book)
{
    entitySave(book)
}

function onMissingMethod( string MethodName , struct MethodArgs )
{
    if ( NOT StructKeyExists(Variables,Arguments.MethodName) )
    {
        throw("The method #Arguments.MethodName# was not found");
    }

    try
    {
        var Meth = Variables[Arguments.MethodName];
        Meth( ArgumentCollection=Arguments.MethodArgs );
    }
    catch(any e)
    {
        var message = "Error accessing database, ";

        switch(MethodName)
        {
            case "GetAll":
                message &= "could not read";
            break;
            case "Save":
                message &= "could not save";
            break;
        }

        throw (type="CustomException,message=message);
    }
}
...