问题
Groovy is so powerful I wonder whether there's an easy way to do this.
The scenario:
I have an abstract class, AbstractSequence
. Then I have two (more in reality) subclasses, called say CasedSequence
and LowerCaseSequence
. Each of these concrete classes has to have an "identity map", i.e. like a Set
but where it is possible to extract an element based on functional equality (overriding of equals
and hashCode
).
So we have:
class CasedSequence extends AbstractSequence {
static Map identityMap = [:]
...
class LowerCaseSequence extends AbstractSequence {
static Map identityMap = [:]
In fact, for reasons that would take too long to explain, manipulation of these identity maps in the respective classes also uses lots of static methods, all similar/identical from one subclass to the other. So I wondered how one might refactor to put the identity maps in the abstract base class (and then migrate a lot of the repetitive static methods there).
This led me to this:
abstract class AbstractSequence {
static Map getIdentityMap( Class clazz ) {
if( ! ( clazz in identityMaps ))
identityMaps[ clazz ] = [ : ]
identityMaps[ clazz ]
}
static Map identityMaps = [:]
and then in the concrete classes, each time you want to use the identity map you have to do this:
class CasedSequence extends AbstractSequence {
def someMethod( CasedSequence seq1 ){
CasedSequence seq2 = getIdentityMap( CasedSequence )[ seq1 ]
...
Again, it's too complicated to explain why you need to retrieve things this way... but I'm just wondering whether there's a way (an elegant Groovy way?) in AbstractSequence.getIdentityMap()
to identify the class of the subclass calling getIdentityMap()
, rather than having to pass this class as a parameter?
PS I'd rather not use Thread.stackTrace
: it's cumbersome and won't deliver the actual class object, only the class name, and also stack traces in Groovy are wild. I'm thinking more in terms of Groovy reflection, Groovy metaclasses...
回答1:
Would be interested in hearing from any Groovy gurus about this.
In the mean time I have used a bit of Groovy magic for a workaround, taking advantage of the fact that the Groovy GDK adds some methods to the class
class, one being newInstance()
- pretty useful. This "makes or gets" a sequence object depending on whether or not the sought sequence is already in the identity map.
static makeOrGet( String string, Class clazz ) {
def dummySeq = clazz.newInstance( DUMMY_STRING )
// NB the constructor identifies the string DUMMY_STRING to prevent this new object being
// properly "registered" (i.e. put in the identity map), which would be wrong because
// the dummy seq is just to find out whether the sequence with "string" is actually
// present in the map
def seq
// disguise the dummy sequence to flush out an existing sequence with String "string"
dummySeq.string = string
if( dummySeq in getIdentityMap( clazz ) )
seq = getIdentityMap( clazz )[ dummySeq ]
else
// NB constructor puts the new "clazz" object in the identity map
seq = clazz.newInstance( string )
seq
}
... so the above method can be called with various different classes as parameter 2 and then delivers an object of class clazz
, either extracted from the identity map or constructed (and put in the map).
来源:https://stackoverflow.com/questions/57019972/any-way-in-groovy-java-to-identify-the-subclass-calling-a-static-method