简体   繁体   中英

How can I create an instance of a derived class from an instance of a base class and include private fields?

My question is kind of related to this question but a bit more specific.

I have a domain object Customer that looks like this:

public class Customer : Party
{
    public Identity Identity {get; protected set;}
    public bool IsOrganization {get; set;}
}

and Identity looks like this:

public class Identity : PersistableModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string MiddleInitial { get; set; }
    public string Title { get; set; }
    public string BusinessName { get; set; }
    public string LegalName { get; set; }
    public bool IsSynchronized { get; private set; }
}

public abstract class PersistableModel : IPersistableModel
{
    public const long UnassignedId = 0;
    public static readonly DateTime MinimumDateTime = new DateTime(1900, 1, 1);

    private readonly List<string> modifiedProperties = new List<string>();
    public virtual ModelState State { get; set; }
    public IEnumerable<string> ModifiedProperties { get { return modifiedProperties; } }
    protected bool HasModifiedProperties { get { return 0 < modifiedProperties.Count; } }
    public bool WasModified(string propertyName)
    {
        return modifiedProperties.Contains(propertyName);
    }
    public void WasModified(string propertyName, bool modified)
    {
        if (modified)
        {
            if (!WasModified(propertyName)) modifiedProperties.Add(propertyName);
        }
        else 
        {
            modifiedProperties.Remove(propertyName);
        }
    }

    public virtual void OnPersisting()
    {
    }

    public abstract void Accept(Breadcrumb breadcrumb, IModelVisitor visitor);
}

Now based on the value of IsOrganization some logic within Identity needs to change, specifically if IsOrganization is true the Individual related fields (first name, last name, etc...) need to return null and when it is false the Organization fields need to return null.

Previously this was done by having different implementations of the customer that would initialize the identity to different base class in their constructors however the change I'm working on needs to remove the class separation of these two customer types.

What I was thinking is for the Identity property to look something like this:

public override Identity Identity
{
    get
    {
         if (IsOrganization)
         {
             return OrgnaizationIdentity.FromIdentity(base.Identity);
         }
         else
         {
             return IndividualIdentity.FromIdentity(base.Identity);
         }
     } 
 }

and the From Identity method looks like this:

public static OrgnaizationIdentity FromIdentity(Identity identity)
{
    return new OrgnaizationIdentity
    {
        FirstName = identity.FirstName,
        LastName = identity.LastName,
        MiddleNameInitial = identity.MiddleNameInitial,
        Title = identity.Title
    };
}

The problem here is the original identity object has some private fields that need to be returned as well.

So my question is, is there an accepted way of doing something like this?

A Copy constructor can do this, if you can add and use one:

class Identity
{
    private int x;
    public Identity(Identity that)
    {
        this.x = that.x;
    }
}

class OrgnaizationIdentity : Identity 
{
    public OrgnaizationIdentity(Identity that) : base(that) { ... }
}

Not sure why you wouldn't just mark the attribs as public or even protected if these are truly subclassed (i'm guess they are), but here is a hack around it.

Why not create static factory methods on the Identity class? That way you have access to private members of the Identity? It seems to me you are implementing the anti pattern known as the 'Anemic data model' by having other classes responsible for the creation of another business object.

Why couldn't you add something like this to your Identity class:

public static Identity CreateIdentity(Customer from)
{
     Identity newId = null;
     //call other factory....
     if (from.IsOrganization)
     {
         newId =  OrgnaizationIdentity.FromIdentity(from);
     }
     else
     {
         newId = IndividualIdentity.FromIdentity(from);
     }

     //populate Identity private attribs here...
} 

This allows the other factory methods to create the subclasses... but allows the Identity factory to see the private vars...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM