In Sharp6502 (my 6502 emulation engine written in C#) I treat internal registers and external memory both as first-class objects - the MemoryManager class instantiates an object for external memory, and another for internal registers, mapped to a different numeric range. Consequently, memory access and register access are identical at the functional level, since they are both referenced through MemoryManager according to what is basically an index.
Address-mode differentiation is simply a matter of filtering the bit-pattern of the instruction under emulation and performing a very simple calculation to determine the index to be passed to the MemoryManager - this might be implied, or require one or two further bytes, but the underlying mechanism is identical for every instruction.