diff --git a/src/matcher.c b/src/matcher.c
index c237329..fd1b25a 100644
--- a/src/matcher.c
+++ b/src/matcher.c
@@ -28,32 +28,26 @@ #include "table.h"
 #include "trie.h"
 
 struct _vte_matcher {
-	gboolean initialized;
-	enum {
-		_vte_matcher_table,
-		_vte_matcher_trie
-	} type;
-	struct _vte_table *table;
-	struct _vte_trie *trie;
+	_vte_matcher_match_func match; /* shortcut to the most common op */
+	struct _vte_matcher_impl *impl;
 };
 
 static GStaticMutex _vte_matcher_mutex = G_STATIC_MUTEX_INIT;
 static GCache *_vte_matcher_cache = NULL;
+static struct _vte_matcher_impl dummy_vte_matcher_trie = {
+	&_vte_matcher_trie
+};
+static struct _vte_matcher_impl dummy_vte_matcher_table = {
+	&_vte_matcher_table
+};
 
 /* Add a string to the matcher. */
 static void
-_vte_matcher_add(struct _vte_matcher *matcher,
+_vte_matcher_add(const struct _vte_matcher *matcher,
 		 const char *pattern, gssize length,
 		 const char *result, GQuark quark)
 {
-	switch (matcher->type) {
-	case _vte_matcher_table:
-		_vte_table_add(matcher->table, pattern, length, result, quark);
-		break;
-	case _vte_matcher_trie:
-		_vte_trie_add(matcher->trie, pattern, length, result, quark);
-		break;
-	}
+	matcher->impl->klass->add(matcher->impl, pattern, length, result, quark);
 }
 
 /* Loads all sequences into matcher */
@@ -145,25 +139,14 @@ #ifdef VTE_DEBUG
 	}
 #endif
 	ret = g_slice_new(struct _vte_matcher);
-	ret->initialized = FALSE;
-	ret->type = _vte_matcher_trie;
-	ret->table = NULL;
-	ret->trie = NULL;
+	ret->impl = &dummy_vte_matcher_trie;
+	ret->match = NULL;
 
 	if (strcmp(emulation, "xterm") == 0) {
-		ret->type = _vte_matcher_table;
+		ret->impl = &dummy_vte_matcher_table;
 	} else
 	if (strcmp(emulation, "dtterm") == 0) {
-		ret->type = _vte_matcher_table;
-	}
-
-	switch (ret->type) {
-	case _vte_matcher_table:
-		ret->table = _vte_table_new();
-		break;
-	case _vte_matcher_trie:
-		ret->trie = _vte_trie_new();
-		break;
+		ret->impl = &dummy_vte_matcher_table;
 	}
 
 	return ret;
@@ -180,12 +163,8 @@ #ifdef VTE_DEBUG
 		g_printerr("_vte_matcher_destroy()\n");
 	}
 #endif
-	if (matcher->table != NULL) {
-		_vte_table_free(matcher->table);
-	}
-	if (matcher->trie != NULL) {
-		_vte_trie_free(matcher->trie);
-	}
+	if (matcher->match != NULL) /* do not call destroy on dummy values */
+		matcher->impl->klass->destroy(matcher->impl);
 	g_slice_free(struct _vte_matcher, matcher);
 }
 
@@ -209,9 +188,10 @@ _vte_matcher_new(const char *emulation, 
 
 	ret = g_cache_insert(_vte_matcher_cache, (gpointer) emulation);
 
-	if (!ret->initialized) {
+	if (ret->match == NULL) {
+		ret->impl = ret->impl->klass->create();
+		ret->match = ret->impl->klass->match;
 		_vte_matcher_init(ret, emulation, termcap);
-		ret->initialized = TRUE;
 	}
 
 	g_static_mutex_unlock(&_vte_matcher_mutex);
@@ -235,31 +215,15 @@ _vte_matcher_match(struct _vte_matcher *
 		   const char **res, const gunichar **consumed,
 		   GQuark *quark, GValueArray **array)
 {
-	switch (matcher->type) {
-	case _vte_matcher_table:
-		return _vte_table_match(matcher->table, pattern, length,
+	return matcher->match(matcher->impl, pattern, length,
 					res, consumed, quark, array);
-		break;
-	case _vte_matcher_trie:
-		return _vte_trie_match(matcher->trie, pattern, length,
-				       res, consumed, quark, array);
-		break;
-	}
-	return NULL;
 }
 
 /* Dump out the contents of a matcher, mainly for debugging. */
 void
 _vte_matcher_print(struct _vte_matcher *matcher)
 {
-	switch (matcher->type) {
-	case _vte_matcher_table:
-		_vte_table_print(matcher->table);
-		break;
-	case _vte_matcher_trie:
-		_vte_trie_print(matcher->trie);
-		break;
-	}
+	matcher->impl->klass->print(matcher->impl);
 }
 
 /* Free a parameter array.  Most of the GValue elements can clean up after
diff --git a/src/matcher.h b/src/matcher.h
index 95bab56..e291792 100644
--- a/src/matcher.h
+++ b/src/matcher.h
@@ -29,6 +29,29 @@ G_BEGIN_DECLS
 
 struct _vte_matcher;
 
+struct _vte_matcher_impl {
+	const struct _vte_matcher_class *klass;
+	/* private */
+};
+
+typedef struct _vte_matcher_impl *(*_vte_matcher_create_func)(void);
+typedef const char *(*_vte_matcher_match_func)(struct _vte_matcher_impl *impl,
+		const gunichar *pattern, gssize length,
+		const char **res, const gunichar **consumed,
+		GQuark *quark, GValueArray **array);
+typedef void (*_vte_matcher_add_func)(struct _vte_matcher_impl *impl,
+		const char *pattern, gssize length,
+		const char *result, GQuark quark);
+typedef void (*_vte_matcher_print_func)(struct _vte_matcher_impl *impl);
+typedef void (*_vte_matcher_destroy_func)(struct _vte_matcher_impl *impl);
+struct _vte_matcher_class{
+	_vte_matcher_create_func create;
+	_vte_matcher_add_func add;
+	_vte_matcher_print_func print;
+	_vte_matcher_match_func match;
+	_vte_matcher_destroy_func destroy;
+};
+
 /* Create and init matcher. */
 struct _vte_matcher *_vte_matcher_new(const char *emulation,
 				      struct _vte_termcap *termcap);
diff --git a/src/table.c b/src/table.c
index 728f076..96e13be 100644
--- a/src/table.c
+++ b/src/table.c
@@ -42,6 +42,7 @@ #define _vte_table_is_numeric(__c) \
 	(((__c) >= '0') && ((__c) <= '9'))
 
 struct _vte_table {
+	struct _vte_matcher_impl impl;
 	GQuark resultq;
 	const char *result;
 	unsigned char *original;
@@ -68,7 +69,10 @@ struct _vte_table_arginfo {
 struct _vte_table *
 _vte_table_new(void)
 {
-	return g_slice_new0(struct _vte_table);
+	struct _vte_table * ret;
+	ret = g_slice_new0(struct _vte_table);
+	ret->impl.klass = &_vte_matcher_table;
+	return ret;
 }
 
 struct _vte_table **
@@ -854,3 +858,11 @@ main(int argc, char **argv)
 	return 0;
 }
 #endif
+
+const struct _vte_matcher_class _vte_matcher_table = {
+	(_vte_matcher_create_func)_vte_table_new,
+	(_vte_matcher_add_func)_vte_table_add,
+	(_vte_matcher_print_func)_vte_table_print,
+	(_vte_matcher_match_func)_vte_table_match,
+	(_vte_matcher_destroy_func)_vte_table_free
+};
diff --git a/src/table.h b/src/table.h
index 6c8075c..31989f2 100644
--- a/src/table.h
+++ b/src/table.h
@@ -47,6 +47,8 @@ const char *_vte_table_match(struct _vte
 /* Dump out the contents of a tree. */
 void _vte_table_print(struct _vte_table *table);
 
+extern const struct _vte_matcher_class _vte_matcher_table;
+
 G_END_DECLS
 
 #endif
diff --git a/src/trie.c b/src/trie.c
index 8842479..3b288ed 100644
--- a/src/trie.c
+++ b/src/trie.c
@@ -92,6 +92,7 @@ struct char_class {
 
 /* A trie to hold control sequences. */
 struct _vte_trie {
+	struct _vte_matcher_impl impl;
 	const char *result;		/* If this is a terminal node, then this
 					   field contains its "value". */
 	GQuark quark;			/* The quark for the value of the
@@ -374,7 +375,10 @@ static struct char_class char_classes[] 
 TRIE_MAYBE_STATIC struct _vte_trie *
 _vte_trie_new(void)
 {
-	return g_slice_new0(struct _vte_trie);
+	struct _vte_trie *ret;
+	ret = g_slice_new0(struct _vte_trie);
+	ret->impl.klass = &_vte_matcher_trie;
+	return ret;
 }
 
 TRIE_MAYBE_STATIC void
@@ -1104,3 +1108,11 @@ main(int argc, char **argv)
 	return 0;
 }
 #endif
+
+const struct _vte_matcher_class _vte_matcher_trie = {
+	(_vte_matcher_create_func)_vte_trie_new,
+	(_vte_matcher_add_func)_vte_trie_add,
+	(_vte_matcher_print_func)_vte_trie_print,
+	(_vte_matcher_match_func)_vte_trie_match,
+	(_vte_matcher_destroy_func)_vte_trie_free
+};
diff --git a/src/trie.h b/src/trie.h
index 47643d8..3e23c2c 100644
--- a/src/trie.h
+++ b/src/trie.h
@@ -58,6 +58,8 @@ const char *_vte_trie_match(struct _vte_
 /* Print the contents of the trie (mainly for diagnostic purposes). */
 void _vte_trie_print(struct _vte_trie *trie);
 
+extern const struct _vte_matcher_class _vte_matcher_trie;
+
 G_END_DECLS
 
 #endif
