Иерархия / Flyweight / Проблема экземпляра в Python - PullRequest
0 голосов
/ 26 марта 2009

Вот проблема, которую я пытаюсь решить (я упростил реальную проблему, но она должна дать вам всю необходимую информацию). У меня иерархия примерно такая:

1.A
1.B
1.C
2.A
3.D
4.B
5.F

(Это трудно проиллюстрировать - каждое число является родителем, каждая буква - ребенком).

  1. Создание экземпляра объектов 'letter' стоит дорого (ввод-вывод, затраты на базу данных и т. Д.), Поэтому его следует выполнять только один раз.

  2. Иерархия должна быть удобной для навигации.

  3. У детей в иерархии должен быть только один родитель.

  4. Изменение содержимого буквенных объектов должно быть возможным непосредственно из объектов в иерархии.

  5. Должен быть центральный склад, содержащий все объекты «буквы» (и только те, которые находятся в иерархии).

  6. Необходимо создать объекты 'letter' и 'number' из конструктора (например, Letter (** kwargs)).

  7. Вполне допустимо ожидать, что при изменении буквы в иерархии все остальные буквы будут учитывать то же изменение.

Надеюсь, это не слишком абстрактно, чтобы проиллюстрировать проблему.

Каков наилучший способ решения этой проблемы? (Тогда я выложу свое решение)

Вот пример сценария:

one = Number('one')
a = Letter('a')
one.addChild(a)
two = Number('two')
a = Letter('a')
two.addChild(a)

for child in one:
    child.method1()
for child in two:
    print '%s' % child.method2()

1 Ответ

0 голосов
/ 26 марта 2009

Базовый подход будет использовать встроенные типы данных. Если я получу ваш дрейф, объект Letter должен быть создан на фабрике с кэшем dict, чтобы сохранить ранее сгенерированные объекты Letter. Фабрика создаст только один Letter объект для каждого ключа.

Объект Number может быть подклассом list, который будет содержать объекты Letter, так что append() может использоваться для добавления потомка. A list легко ориентироваться.

Грубый план кеширующей фабрики:

>>> class Letters(object):
...     def __init__(self):
...         self.cache = {}
...     def create(self, v):
...         l = self.cache.get(v, None)
...         if l:
...             return l
...         l = self.cache[v] = Letter(v)
...         return l
>>> factory=Letters()
>>> factory.cache
{}
>>> factory.create('a')
<__main__.Letter object at 0x00EF2950>
>>> factory.create('a')
<__main__.Letter object at 0x00EF2950>
>>> 

Чтобы выполнить требование 6 (конструктор), вот более надуманный пример, использующий __new__ конструктора кэширования. Это похоже на Рецепт 413717: Создание объекта кэширования .

class Letter(object):
    cache = {}

    def __new__(cls, v):
        o = cls.cache.get(v, None)
        if o:
            return o
        else:
            o = cls.cache[v] = object.__new__(cls)
            return o

    def __init__(self, v):
        self.v = v
        self.refcount = 0

    def addAsChild(self, chain):
        if self.refcount > 0:
            return False
        self.refcount += 1
        chain.append(self)
        return True

Проверка работоспособности кеша

>>> l1 = Letter('a')
>>> l2 = Letter('a')
>>> l1 is l2
True
>>> 

Для принудительного использования одного родителя вам понадобится метод для Letter объектов (не Number) - со счетчиком ссылок. При вызове для добавления он будет отклонять добавление, если счетчик больше нуля.

l1.addAsChild(num4)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...