4

何かを表すオブジェクトは、メモリ内に1つのインスタンスしか持てないと思います。私は重複して等しいオブジェクトを持つことを避けます。

  1. Cityキャッシュ(拡張)に含まれる、 タイプが「ニューヨーク」によって一意に識別されるオブジェクトを想定しますSystem.Runtime.Caching.ObjectCache。このオブジェクトは、と呼ばれる別のオブジェクトによって参照されますMyBusinessObject

  2. キャッシュは「NewYork」オブジェクトを削除しますが、オブジェクトMyBusinessObjectは引き続き「NewYork」を参照します。ガベージコレクタは、まだ参照があるため、このオブジェクトをメモリから削除しません。

  3. 別のオブジェクトがキャッシュから「ニューヨーク」を要求します。Cityキャッシュは「ニューヨーク」の新しいインスタンスをロードします

これで、「ニューヨーク」の2つのインスタンスがあります。1つMyBusinessObjectは参照している(無効になっている)もので、もう1つはキャッシュが参照している「ニューヨーク」の新しいインスタンスです。

この問題を解決するデザインパターンはありますか?MyBusinessObjectの古いインスタンスを使用したくありませんCity

考えられる解決策の1つは、参照されているキャッシュオブジェクトを削除しないことですが、これを行うにはどうすればよいですか?

これが私が上で説明しようとしていることのUML図です:

クラス図UML

オブジェクト図

4

1 に答える 1

2

この場合、キャッシュは実際のオブジェクトをキャッシュするのではなく、キャッシュされているオブジェクトのラッパーであり、キャッシュ内のオブジェクトの状態に関する情報も含まれている必要があります。

たとえば、キャッシュ内のアイテムを表す、このような単純なクラスを作成できます。

public class CacheItem<T>
{
    // Since the cache is the only thing
    // that should be making CacheItems,
    // make this internal to the assembly
    // that the cache is implemented in.
    // This constructor is called before
    // an add.
    internal CacheItem(T item)
    {
        // Set the property values.
        Item = item;
    }

    // Poor-man's immutability.
    public T Item { get; private set; }

    // The backing field for IsCached, it
    // is volatile so that it can serialize
    // access for single reads/writes, which is
    // what the property does.
    // Assume it is being added when constructed.
    private volatile bool _isCached = true;

    // Only able to be set by the cache.
    // The setter is set to false when the item
    // is stale (not in the cache any longer).
    public bool IsCached 
    {
        get { return _isCached; }
        set { _isCached = value; } 
    }
}

ここでの考え方は単純です。

  • キャッシュがアイテムの新しいインスタンスをキャッシュに入力しようとすると、コンストラクターが呼び出されます(コンストラクターはキャッシュでのみ使用可能である必要があります。必要に応じて、CacheItem内部ではなくプライベートコンストラクターを使用してネストされたクラスを作成できます)これにより、IsCachedプロパティ値がtrueに設定されます。その後、アイテムはキャッシュに配置されます。

  • アイテムがキャッシュから期限切れになると、キャッシュはIsCachedプロパティをfalseに設定します(この場合も、このプロパティにはキャッシュからのみアクセスできる必要があります)。

  • 責任はクライアントCacheItem<T>に移され、古いかどうかを確認します。

これはプル操作であることに注意してください。必要に応じて、次のようにイベントを追加することで、プッシュ操作のサポートを追加できます。CacheItem<T>

public class CacheItem<T>
{
    // Since the cache is the only thing
    // that should be making CacheItems,
    // make this internal to the assembly
    // that the cache is implemented in.
    // This constructor is called before
    // an add.
    internal CacheItem(T item)
    {
        // Set the property values.
        Item = item;
    }

    // Poor-man's immutability.
    public T Item { get; private set; }

    // The lock for the event registrations.
    // Since everything else is immutable, this needs
    // to be as well.
    private readonly object _eventLock = new object();

    // The backing field for the Expired
    // event.  Since everything else is immutable
    // this needs to be as well.
    private readonly EventHandler _expiredHandlers;

    // The expires event.
    public event EventHandler Expired
    {
        add { lock (_eventLock) _expiredHandlers += value; }
        remove { lock (_eventLock) _expiredHandlers -= value; }
    }

    // The backing field for IsCached, it
    // is volatile so that it can serialize
    // access for single reads/writes, which is
    // what the property does.
    // Assume it is being added when constructed.
    private volatile bool _isCached = true;        

    // The setter is set to false by the 
    // Expire method (called by the cached)
    // when the item is stale 
    // (not in the cache any longer).
    public bool IsCached { get { return _isCached; } }

    // Called internally by the cache.
    internal void Expire()
    {
        // Set _isCached to false.
        _isCached = false;

        // Get the event handlers and fire
        // the event.  Getting the handlers
        // needs to be synchronized.
        EventHandler handlers;

        // Synchronize.
        lock (_eventLock) handlers = _expiredHandlers;

        // Fire if there are handlers.
        if (handlers != null) handlers(this, EventArgs.Empty);
    }
}

これで、クライアントにイベントをサブスクライブさせることができます。Expiredこれにより、キャッシュアイテムが無効になったときにクライアントに通知されます。Expireこれは、アイテムがキャッシュから削除されたときにアイテムの内部イベントを呼び出すことによってキャッシュによって発生します(また、IsCachedプロパティもfalseに設定されます)。

于 2012-11-14T14:27:29.203 に答える