As we have discussed that in the previous post - composite from two classes, we have examine the ways that to compose characteristic from two classes, well to a certain degree we have achieved the goal, but we left a hole where it may expose interface for compromise.
the design rule to tell us we should separate interface from its implementaiton, and interface is the key to this design.
however, we won't do IDictionary<string, TableId> as there are so interfaces that needs to be filled, and some are not necessary if we just want to maintain a inverse look up table.
then it occurs to me how about if we can simulate only part of the interface (maybe borrow/clone part of the target inteface).
with this in mind, we can make a new interface as such.
public interface ITableDictBase { void Add(string key, TableID tableId); TableID this[string key] {get; set;} void Remove(string key); Dictionary<string, TableID>.KeyCollection Keys { get; } Dictionary<string, TableID>.ValueCollection Values { get; } bool ContainsKey(string key); }and we will make yet another interface with an additional member so we can have a inverse lookup ability .
internal interface ITableDict : ITableDictBase { string GetTableId(int innerId); }so, we go ahead, with the separation.
public class TableIdDictWrapper : ServiceSingletonBase<TableIdDictWrapper> { // TODO: // reverse look up table from int -> TableId private InnerTableIdDict _tableIdDict = new InnerTableIdDict(); public ITableDictBase TableIdDict { get { return _tableIdDict; } } internal ITableDict TableIdDictExtended { get { return _tableIdDict; } } // You can add something that helps you with private class InnerTableIdDict : TableIdDict { internal InnerTableIdDict() { } } }we have an private class which serves a way to hide. and we expose two properties, each is under a the sealed interface, one is public used to expose to the general public, and another is internal one, which we wish to exposed internally so we can have the concealed reverse lookup ability.
// you can even create a publich TableIdDict internal abstract class TableIdDict : Dictionary<string, TableID>, ITableDict { protected internal TableIdDict() { } // prevent it from being created outside protected Dictionary<int, TableID> _reverseDict = new Dictionary<int,TableID>(); void ITableDictBase.Add(string key, TableID tableId) { if (key == null) throw new ArgumentNullException("key"); base.Add(key, tableId); _reverseDict.Add(tableId.InnerTableId, tableId); } TableID ITableDictBase.this[string key] { get { return base[key]; } set { if (base.ContainsKey(key)) // update { var innerId = base[key].InnerTableId; base[key] = value; _reverseDict[innerId] = value; } else // Add { ((ITableDictBase)this).Add(key, value); } } } void ITableDictBase.Remove(string key) { if (key == null) throw new ArgumentNullException("key"); if (base.ContainsKey(key)) { var tableId = base[key]; base.Remove(key); _reverseDict.Remove(tableId.InnerTableId); } } string ITableDict.GetTableId(int innerId) { if (_reverseDict.ContainsKey(innerId)) { return _reverseDict[innerId].Name; } else throw new ArgumentException("Invalid InnerId provided!"); } }As we have seen, the TableIdDict serves the main implementation of the ITabledDict interface. and the default impl from Dictionary<string, TableId>lays the meat and potatoes of the impl.