В настоящее время я работаю над проектом, который требует общего интерфейса для определения, совместного использования и поиска иерархии объектов. По сути, это будет общий проект, который определяет общую структуру для всех объектов, и проекты-потребители могут использовать ее для определения объектов и совместного использования их среди других проектов. Мне интересно, существует ли существующий шаблон проектирования, который соответствует этому и реализует это хорошо.
Я уже пытался это сделать, но я не совсем удовлетворен результатами. Мой текущий подход определяет класс Tag
, который использует уникальный string
в качестве имени, и Guid
в качестве идентификатора, генерируемого во время выполнения, для более быстрого поиска (хеширование и приравнивание значений Guid
выполняется намного быстрее, чем при работе со строками ). Затем объекты, которые я хочу использовать в глобальных проектах, определяют, что Tag
является участником.
В этом текущем проекте объекты Tag
служат исключительно в качестве идентификатора и не содержат данных. Я хотел бы изменить дизайн так, чтобы теги содержали данные и служили базовым классом. Однако это становится все более сложным, и поэтому я надеюсь найти установленные шаблоны проектирования или существующие проекты, которые реализуют аналогичную систему для помощи в разработке.
[DebuggerDisplay( "Name = {Name}, Children = {ChildCount}" )]
public class Tag : IDisposable, IEquatable<Tag>
{
#region Data Members
public readonly Guid Id;
public readonly string Name;
public readonly string FullName;
public readonly Tag Parent;
protected readonly HashSet<Tag> children_;
protected readonly int hash_;
protected bool isDisposed_;
#endregion
#region Properties
public IReadOnlyCollection<Tag> Children
{
[MethodImpl( MethodImplOptions.AggressiveInlining )]
get => children_;
}
public int ChildCount
{
[MethodImpl( MethodImplOptions.AggressiveInlining )]
get => children_.Count;
}
public bool HasChildren
{
[MethodImpl( MethodImplOptions.AggressiveInlining )]
get => children_.Count > 0;
}
public bool HasParent
{
[MethodImpl( MethodImplOptions.AggressiveInlining )]
get => Parent != null;
}
#endregion
#region Constructor
public Tag( string name )
: this( Guid.NewGuid(), name, null )
{
}
public Tag( string name, Tag parent )
: this( Guid.NewGuid(), name, parent )
{
}
public Tag( Guid id, string name )
: this( id, name, null )
{
}
public Tag( Guid id, string name, Tag parent )
{
Id = id;
FullName = Name = name;
children_ = new HashSet<Tag>();
hash_ = Name.GetHashCode( StringComparison.InvariantCultureIgnoreCase );
if( parent != null )
{
Parent = parent;
FullName = $"{parent.FullName}.{Name}";
Parent.AddChild( this );
}
}
~Tag()
{
Dispose( false );
}
#endregion
#region Public Methods
[MethodImpl( MethodImplOptions.AggressiveInlining )]
internal void AddChild( Tag child )
{
if( !children_.Add( child ) )
{
children_.TryGetValue( child, out var existingChild );
throw new DuplicateTagChildException( this, existingChild, child );
}
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
internal void RemoveChild( Tag child )
{
children_.Remove( child );
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public bool HasChild( Tag child )
{
return children_.Contains( child );
}
#endregion
#region Overrides
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public bool Equals( Tag other )
{
return Name.Equals( other.Name, StringComparison.InvariantCultureIgnoreCase );
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public override bool Equals( object obj )
{
return obj is Tag other
&& Name.Equals( other.Name, StringComparison.InvariantCultureIgnoreCase );
}
[MethodImpl( MethodImplOptions.AggressiveInlining )]
public override int GetHashCode()
{
return hash_;
}
#endregion
#region IDisposable Methods
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
public virtual void Dispose( bool disposing )
{
if( isDisposed_ )
return;
if( disposing )
{
}
Parent?.RemoveChild( this );
TagCache.TryRemove( this );
isDisposed_ = true;
}
#endregion
}