在软件系统中,必须在两个对象之间建立一对一关系,其中关系存在活动状态。
换句话说,ObjectA与ObjectB(没有后向指针)具有一对一的关系,其中关系可以是活动的或非活动的。可能还有与该关系相关的其他属性。
在.NET中使用面向对象建模此方案的最佳方法是什么?
答案 0 :(得分:9)
这取决于激活关系是否是您要建模的系统行为的一部分。
“可能还有与该关系相关的其他属性。”
所以听起来你想要的模型不仅仅是一个参考。 包含b的实例将在简单的情况下工作,其中关系不是系统行为的一部分,而只是技术实现。
如果要激活/取消激活/激活(不知道/记住对象B已激活),“空建模”将不起作用(因为您将丢失该引用,并且您将丢失有关该关系的信息)。或者例如,在稍后阶段,您希望重新激活关系,而不是引用a和b,而是关系。 因此,将这种关系视为该模型的一等公民。
然后你可以做这样的事情(但这可能是完全矫枉过正的,只是为了显示关系的建模作为你域的一部分):
(来源:googlecode.com)
objectA使用ObjectB代理,它将充当ObjectB,但实际上它引用了与ObjectB的单向关系。 ObjectB代理可以实现关系不活动时要执行的操作。
在代码中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public interface IActivatable
{
void Activate();
void Deactivate();
bool IsActive { get; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public interface IRelationShip<TSource,TDestination> : IActivatable
{
TDestination Destination { get; }
TSource Source { get; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public class ObjectA
{
// you could also have an ObjectB reference here
// and fill it with an ObjectBProxy instance
// in the constructor. thought this would
// explain the example a bit better
private readonly ObjectBProxy proxy;
public ObjectA(ObjectB b)
{
proxy = new ObjectBProxy(b);
}
public void AMethodUsingB()
{
proxy.BMethod();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public class ObjectB
{
public virtual void BMethod()
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public class ObjectBProxy : ObjectB, IActivatable
{
private readonly UniDirectionalRelationship<ObjectB> relation;
public ObjectBProxy(ObjectB to)
{
this.relation = new UniDirectionalRelationship<ObjectB>(to);
}
public override void BMethod()
{
if (relation.IsActive)
{
relation.Destination.BMethod();
} else
{
// do some specific logic here
}
}
public void Activate()
{
relation.Activate();
}
public void Deactivate()
{
relation.Deactivate();
}
public bool IsActive
{
get { return relation.IsActive; }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public class RelationshipNotActiveException : Exception
{
public RelationshipNotActiveException(string message) : base(message)
{
}
public RelationshipNotActiveException(string message, Exception innerException) : base(message, innerException)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ActivatableRelationshipExample
{
public class UniDirectionalRelationship<TDestination> : IRelationShip<object,TDestination> where TDestination :class
{
private bool active = true;
private readonly TDestination destination;
public UniDirectionalRelationship(TDestination destination)
{
if(destination == null)
{
throw new ArgumentNullException("destination","destination cannot be null");
}
this.destination = destination;
}
public void Activate()
{
active = true;
}
public void Deactivate()
{
active = false;
}
public virtual bool IsActive
{
get { return active; }
}
public virtual TDestination Destination
{
get
{
if (active)
{
return destination;
}
throw new RelationshipNotActiveException("the relationship is not active");
}
}
public virtual object Source
{
get { throw new NotSupportedException("Source is not supported"); }
}
}
}
答案 1 :(得分:3)
包含ObjectB实例的ObjectA。非活动表示为空,否则为活动。
答案 2 :(得分:0)
我认为你想要的是一个客观化的关系或客体化的关联。基本上你的关系是一个可以拥有属性,状态等的第一类对象...
Kyle Baley查看this blog post。在他的案例中,他谈论的是多对多的关联,但我认为这种模式也可以在一对一的情况下发挥作用。请务必仔细阅读博客评论。