Я хотел бы реорганизовать класс Cache
, чтобы он не нарушал принцип единой ответственности (SRP).
Однако мне трудно понять, как я могу преобразовать ненужные шаги в Cache
классе в memoize
функцию. В идеале у меня было бы два метода в классе Cache
get
и set
function isObject(arg) {
const typeOfObj = typeof arg;
return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}
class Cache {
constructor() {
this.map = new Map();
this.weakmap = new WeakMap();
}
// create or retrieve a nested Cache instance based on an arguments object
get(args) {
let cache = this;
for (const key of args) {
const map = cache[isObject(key) ? 'weakmap' : 'map'];
cache = map.get(key) || map.set(key, new Cache()).get(key);
}
return cache;
}
}
function memoize(fn) {
const cache = new Cache();
return (...args) => {
// get (or create) a cache item
const item = cache.get(args);
if (Reflect.has(item, 'value')) {
return item.value;
}
return (item.value = fn(args));
};
}
let counter = 1;
function foo() {
counter += 1;
return counter;
}
const id1 = Symbol('id');
const id2 = Symbol('id');
const obj1 = { a: 1 };
const obj2 = { a: 1 };
const memoizedFoo = memoize(foo);
console.info(memoizedFoo(id1)); // 2
console.info(memoizedFoo(id1)); // 2
console.info(memoizedFoo(id2)); // 3
console.info(memoizedFoo(id2)); // 3
console.info(memoizedFoo(obj1)); // 4
console.info(memoizedFoo(obj1)); // 4
console.info(memoizedFoo(obj2)); // 5
console.info(memoizedFoo(obj2)); // 5
console.info(memoizedFoo(5)); // 6
console.info(memoizedFoo(5)); // 6
console.info(memoizedFoo(4)); // 7
console.info(memoizedFoo(4)); // 7
Один из вариантов — иметь 3 метода в классе NestedCache
:
Вы можете использовать reduce
для перебора массива ключей вместо постоянного переназначения переменной cache
, чтобы быть немного более функциональным, если хотите.
function isObject(arg) {
const typeOfObj = typeof arg;
return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}
class NestedCache {
constructor() {
this.map = new Map();
this.weakmap = new WeakMap();
}
// retrieve a nested Cache instance based on an array of keys
getNestedMap(keys) {
return keys.reduce((cache, key) => cache.getMap(key), this);
}
// return a Cache's value at a key
getMap(key) {
const map = this[isObject(key) ? 'weakmap' : 'map'];
this.setKeyIfNeeded(map, key);
return map.get(key);
}
// create a Cache's key, if needed
setKeyIfNeeded(map, key) {
if (!map.has(key)) {
map.set(key, new NestedCache());
}
}
}
function memoize(fn) {
const cache = new NestedCache();
return (...args) => {
// get (or create) a cache item
const item = cache.getNestedMap(args);
if (Reflect.has(item, 'value')) {
return item.value;
}
return (item.value = fn(args));
};
}
let counter = 1;
function foo() {
counter += 1;
return counter;
}
const id1 = Symbol('id');
const id2 = Symbol('id');
const obj1 = { a: 1 };
const obj2 = { a: 1 };
const memoizedFoo = memoize(foo);
console.info(memoizedFoo(id1)); // 2
console.info(memoizedFoo(id1)); // 2
console.info(memoizedFoo(id2)); // 3
console.info(memoizedFoo(id2)); // 3
console.info(memoizedFoo(obj1)); // 4
console.info(memoizedFoo(obj1)); // 4
console.info(memoizedFoo(obj2)); // 5
console.info(memoizedFoo(obj2)); // 5
console.info(memoizedFoo(5)); // 6
console.info(memoizedFoo(5)); // 6
console.info(memoizedFoo(4)); // 7
console.info(memoizedFoo(4)); // 7
Технически было бы довольно тривиально переместить getNestedMap
из jsfiddle.net/mnhcp8s3, но я думаю, что все это (а также getMap
и setKeyIfNeeded
) больше связано с NestedCache
, чем что-либо еще.
Я вижу вашу точку зрения. поэтому имеет смысл просто иметь его в классе
Я так думаю - без методов, связанных с вложенными операциями, класс Cache был бы не более чем простым объектом.
Спасибо за ваше объяснение. Я очень ценю это!
Я пытаюсь получить
getNestedMap
изClass
, если это возможно