Mine is a sv based tb and not based on any methodology.
My testcase is a program block and that has the object
of my sequencer class. The sequencer class has lots of interfaces
to it and so the testcase when creating object of the sequencer class,
attaches all the virtual interface objects to it.
program testcase (a_interface a_intf, b_interface b_intf, c_interface c_intf);
env e1;
e1 = new (a_intf, b_intf, c_intf);
e1.start
.
.
.
endprogram
As the chip requirements keeps changing and also the no.of
interfaces keep changing. For every added new interface, the sequencer
class is updated and so the testcase needs to be updated.
program testcase (a_interface a_intf, b_interface b_intf, c_interface c_intf,d_interface d_intf);
env e1;
e1 = new (a_intf, b_intf, c_intf, d_intf);
e1.start
.
.
.
endprogram
Because of this, even the existing testcases needs to be updated which
is becoming an headache. I wrote a workaround using macro that will be
just used in first line of all testcases.
`define program_def program testcase (a_interface a_intf, b_interface b_intf, c_interface c_intf,d_interface d_intf);
Is there any better way to handle new interfaces being added?

Babu,
This is a great example of why you should be using a standard methodology that has solved many of these common problems for you instead of have to re-write them yourself.
This particular problem is called constructor argument bloating where the list of arguments in many places keeps growing and growing. The UVM solved this problem by creating a resource database where you can store and retrieve things by string name or type. Constructor arguments are not used for this. You could use this facility even if you used absolutely nothing else from the UVM. See more details here.
Dave Rich
Mentor Graphics
http://go.mentor.com/drich