There's no real difference between the code on the cookbook page and the code in the p_sequencer macro:
`define uvm_declare_p_sequencer(SEQUENCER) \
virtual function void m_set_p_sequencer();\
if( !$cast(p_sequencer, m_sequencer)) \
$sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name())) \
The more explicit code in the cookbook example is designed to allow users to see what is going on, whereas using the p_sequencer macro hides the code and would require an explanation of the macro and the p_sequencer.
The code shown on the page is also for a virtual sequence base class. Other virtual sequences would inherit from this and simply call super.body() in order to get the sub-sequencer handles assigned.