diff --git a/src/all.js b/src/all.js
index 87ba3bbb9e..64cbbb9ce6 100644
--- a/src/all.js
+++ b/src/all.js
@@ -5,3 +5,4 @@ goog.require('ol.MVCArray');
goog.require('ol.MVCObject');
goog.require('ol.TileBounds');
goog.require('ol.TileCoord');
+goog.require('ol.TileUrl');
diff --git a/src/ol/tileurl.js b/src/ol/tileurl.js
new file mode 100644
index 0000000000..116e20ee64
--- /dev/null
+++ b/src/ol/tileurl.js
@@ -0,0 +1,35 @@
+goog.provide('ol.TileUrl');
+
+goog.require('goog.math');
+goog.require('ol.TileCoord');
+
+
+/**
+ * @typedef {function(ol.TileCoord): string}
+ */
+ol.TileUrlFunction;
+
+
+/**
+ * @param {string} template Template.
+ * @return {ol.TileUrlFunction} Tile URL function.
+ */
+ol.TileUrl.createFromTemplate = function(template) {
+ return function(tileCoord) {
+ return template.replace(/\{z\}/, tileCoord.z)
+ .replace(/\{x\}/, tileCoord.x)
+ .replace(/\{y\}/, tileCoord.y);
+ };
+};
+
+
+/**
+ * @param {Array.
} tileUrlFunctions Tile URL Functions.
+ * @return {ol.TileUrlFunction} Tile URL function.
+ */
+ol.TileUrl.createFromTileUrlFunctions = function(tileUrlFunctions) {
+ return function(tileCoord) {
+ var index = goog.math.modulo(tileCoord.hash(), tileUrlFunctions.length);
+ return tileUrlFunctions[index](tileCoord);
+ };
+};
diff --git a/src/ol/tileurl_test.js b/src/ol/tileurl_test.js
new file mode 100644
index 0000000000..014f044db0
--- /dev/null
+++ b/src/ol/tileurl_test.js
@@ -0,0 +1,20 @@
+goog.require('goog.testing.jsunit');
+goog.require('ol.TileCoord');
+goog.require('ol.TileUrl');
+
+
+function testCreateFromTemplate() {
+ var tileUrl = ol.TileUrl.createFromTemplate('{z}/{x}/{y}');
+ assertEquals('3/2/1', tileUrl(new ol.TileCoord(3, 2, 1)));
+}
+
+
+function testCreateFromTileUrlFunctions() {
+ var tileUrl = ol.TileUrl.createFromTileUrlFunctions([
+ ol.TileUrl.createFromTemplate('a'),
+ ol.TileUrl.createFromTemplate('b')
+ ]);
+ var tileUrl1 = tileUrl(new ol.TileCoord(1, 0, 0));
+ var tileUrl2 = tileUrl(new ol.TileCoord(1, 0, 1));
+ assertTrue(tileUrl1 != tileUrl2);
+}