заводные параметры закрытия - PullRequest
5 голосов
/ 18 мая 2009

Следующий пример использования метода sendMail, предоставляемого почтовым плагином grails, появляется в этой книге .

sendMail {
    to "foo@example.org"
    subject "Registration Complete"
    body view:"/foo/bar", model:[user:new User()]
}

Я понимаю, что код в {} является закрытием, которое передается sendMail в качестве параметра. Я также понимаю, что to, subject и body являются вызовами методов.

Я пытаюсь выяснить, как будет выглядеть код, реализующий метод sendMail, и мое лучшее предположение примерно такое:

MailService {

    String subject
    String recipient
    String view
    def model

    sendMail(closure) {
        closure.call()
        // Code to send the mail now that all the 
        // various properties have been set
    }

    to(recipient) {
        this.recipient = recipient
    }

    subject(subject) {
        this.subject = subject;
    }

    body(view, model) {
        this.view = view
        this.model = model
    }
}

Это разумно, или я что-то упустил? В частности, являются ли методы, вызываемые в замыкании (to, subject, body), обязательно членами того же класса, что и sendMail?

Спасибо, Дон

Ответы [ 2 ]

7 голосов
/ 28 апреля 2010

MailService.sendMail закрытие делегирования:

 MailMessage sendMail(Closure callable) {
    def messageBuilder = new MailMessageBuilder(this, mailSender)
    callable.delegate = messageBuilder
    callable.resolveStrategy = Closure.DELEGATE_FIRST
    callable.call()

    def message = messageBuilder.createMessage()
    initMessage(message)
    sendMail message
    return message
}

и, например, метод для в MailMessageBuilder:

void to(recip) {
    if(recip) {
        if (ConfigurationHolder.config.grails.mail.overrideAddress)
            recip = ConfigurationHolder.config.grails.mail.overrideAddress
        getMessage().setTo([recip.toString()] as String[])
    }
}
1 голос
/ 18 мая 2009

Я точно не знаю, что делает метод sendMail, поскольку у меня нет книги, о которой вы упоминаете. Метод sendMail действительно требует закрытия, как вы описали, но он, вероятно, использует строитель , а не выполняется обычным способом. По сути, это был бы специфичный для домена язык для описания отправляемого электронного письма.

Причина, по которой класс, который вы определили, не будет работать, состоит в том, что область действия замыкания там, где оно объявлено, а не там, где оно запускается. Таким образом, если ваше закрытие вызывает метод to (), он не сможет вызвать метод to в MailService, если вы не передали экземпляр почтового сервиса в замыкание.

С несколькими модификациями ваш пример может работать, хотя и с использованием обычного замыкания. Следующие изменения в вызове и

// The it-> can be omitted but I put it in here so you can see the parameter
service.sendMail {it->
    it.to "foo@example.org"
    it.subject "Registration Complete"
    it.body view:"/foo/bar", model:[user:new User()]
}

Метод sendMail в классе должен выглядеть следующим образом

def sendMail(closure) {
    closure(this)
    // Code to send the mail now that all the 
    // various properties have been set
}
...