Well, one thing I've become very partial towards (because of how easily it allows for extensibility), would be to use blocks as callbacks. However, just breaking up the methods so that they each handle a single responsibility would have been preferred.
Without callbacks, it would look like this:
def use_item item = subject_item targets = subject_use_item(subject, item) target_handle_item(targets, item)enddef subject_item return @subject.current_action.itemenddef subject_use_item(subject, item) @log_window.display_use_item(@subject, item) @subject.use_item(item) refresh_status return @subject.current_action.make_targets.compactenddef targets_handle_item(targets, item) show_animation(targets, item.animation_id) targets.each {|target| target_handle_item(target, item) }enddef target_handle_item(target, item) item.repeats.times { invoke_item(target, item) }endWith a callback and the method breakdown, it would look like this:
def use_item(&callback) item = subject_item targets = subject_use_item(subject, item) target_handle_item(targets, item) callback.call(item, subject, targets) unless callback.nil?enddef subject_item return @subject.current_action.itemenddef subject_use_item(subject, item, &callback) @log_window.display_use_item(@subject, item) return @subject.use_item(item) { |result| refresh_status results = @subject.current_action.make_targets.compact callback.call(item, subject, targets, result) unless callback.nil? results }enddef targets_handle_item(targets, item, &callback) show_animation(targets, item.animation_id) targets.each { |target| target_handle_item(target, item) } callback.call(targets, item) unless callback.nil?enddef target_handle_item(target, item, &callback) item.repeats.times { invoke_item(target, item) } callback.call(target, item) unless callback.nil?endThe advantage with the callback example is that in one-off use cases (perhaps when a subject/target/item is a specific id), you no longer need to override an entire method to do the check. Simply adding a block to the method invocation will let you
append new behaviors for that
specific invocation.
This makes it even more extensible than simple method refactoring and makes it so that the only time you would actually override the method, is if you were truly changing the structure and formula involved in #use_item.
Now, for example, if you want to do something special when the subject id is the current player's actor id, you have some options...
If you want to completely redo the logic:
def subject_use_item(subject, item, &callback) return player_use_item(subject, item, &callback) if subject.id == $game_player.actor.id @log_window.display_use_item(@subject, item) @subject.use_item(item) { |result| refresh_status results = @subject.current_action.make_targets.compact callback.call(item, subject, targets, result) unless callback.nil? results }endIf you want to add new behavior:
Code:
def use_item(&callback) item = subject_item targets = subject_use_item(subject, item) { |item, subject, targets| player_use_item(item, subject, targets) if subject.id == $game_player.actor.id } target_handle_item(targets, item) callback.call(item, subject, targets) unless callback.nil?end