web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested Answer

Interfaces best practices in x++

(0) ShareShare
ReportReport
Posted on by 465

Hi,

I'm trying to create a common class for creating parties
 
As you can see i made a PartyCreatorFactory that detemines whether to call the PersonPartyCreator or OrganiztionPartyCreator.
I also created IPartyCreator interface.

but as you can see the fields needed in person are different than the fields needed in organization  so I had to use object field... what i did is working fine but my question is what is the best way to do it, because i feel like using an object in both classes then checking the type is not the good approach.. so was using interfaces in this case wrong? how would you guys implement it? 

class Party
{
    public PartyNumber createCustomerParty(CustomerReqContract _custDetails)
    {
        DictEnum dictEnum = new DictEnum(enumNum(DirPartyType));
        IPartyCreator partyCreator = PartyCreatorFactory::createParty(dictEnum.symbol2Value(_custDetails.Customer().DirPartyType()));
        if(partyCreator is PersonPartyCreator)
        {
            return partyCreator.createParty(_custDetails.PersonDetails()).PartyNumber;
        }
        else
        {

            return partyCreator.createParty(_custDetails.OrgDetails()).PartyNumber;
        }
    }
}

class PartyCreatorFactory
{

    public static IPartyCreator createParty(DirPartyType _dirPartyType)
    {
        if(_dirPartyType == DirPartyType::Person)
        {
            return new PersonPartyCreator();
        }
        else if(_dirPartyType == DirPartyType::Organization)
        {
            return new OrganizationPartyCreator();
        }
        else
        {
            throw error('Invalid DirPartyType');
        }
    }

}


public interface IPartyCreator
{

    public DirPartyBaseEntity createParty(Object _partyDetails)
    {
    }

}


class PersonPartyCreator implements IPartyCreator
{

    public DirPartyBaseEntity createParty(Object _personDetailsContract)
    {
        DirPartyBaseEntity dirPartyBaseEntity;
        if(_personDetailsContract is PersonDetailsContract)
        {
            PersonDetailsContract custPersonDetails = _personDetailsContract;

            if(custPersonDetails)
            {
                //create Customer details based on DirPartyType which is Person
                dirPartyBaseEntity.initValue();
                dirPartyBaseEntity.PartyType               = enum2Str(DirPartyType::Person);
                dirPartyBaseEntity.PersonFirstName         = custPersonDetails.FirstName();
                dirPartyBaseEntity.PersonMiddleName        = custPersonDetails.MiddleName();
                dirPartyBaseEntity.PersonLastName          = custPersonDetails.LastName();
                dirPartyBaseEntity.PersonPersonalTitle     = custPersonDetails.PersonalTitle();

                RecId NameSequenceRecId = DirNameSequence::find(custPersonDetails.NameSequence()).RecId;
                if(NameSequenceRecId != 0)
                {
                    dirPartyBaseEntity.NameSequence = NameSequenceRecId;
                }
                if(custPersonDetails.BirthDate())
                {
                    dirPartyBaseEntity.PersonBirthDay   = custPersonDetails.BirthDate().BirthDay();
                    dirPartyBaseEntity.PersonBirthMonth = custPersonDetails.BirthDate().BirthMonth();
                    dirPartyBaseEntity.PersonBirthYear  = custPersonDetails.BirthDate().BirthYear();
                }

                dirPartyBaseEntity.insert();
            }
        }

        return dirPartyBaseEntity;
    }

}



class OrganizationPartyCreator implements IPartyCreator
{

    public DirPartyBaseEntity createParty(Object _orgDetailsContract)
    {
        DirPartyBaseEntity dirPartyBaseEntity;

        if(_orgDetailsContract is OrganizationDetailsContract)
        {
            OrganizationDetailsContract orgDetails = _orgDetailsContract;

            if(orgDetails)
            {
                dirPartyBaseEntity.Name = orgDetails.PartyName();
                dirPartyBaseEntity.PartyType = enum2Str(DirPartyType::Organization);
                dirPartyBaseEntity.OrganizationNumber = orgDetails.OrgNumber();
                dirPartyBaseEntity.OrganizationNumOfEmployees = orgDetails.NumberOfEmployees();

                dirPartyBaseEntity.insert();
            }
        }
        
        return dirPartyBaseEntity;
    }

}



I have the same question (0)
  • Martin Dráb Profile Picture
    237,965 Most Valuable Professional on at

    Wouldn't it be better if you pass CustomerReqContract to a creator and let the creator extract the data it needs (by calling personDetails() or orgDetails())?

  • D365FO user Profile Picture
    465 on at

    Hi Martin,

    But the class is called party creator..so I shouldn't pass the customerReqContract because if I want to use it in the future..I might want to use it for vendors for example or anything else. So any other ideas? And is it not a best practice to do it like I did?

  • Martin Dráb Profile Picture
    237,965 Most Valuable Professional on at

    That's easy to solve - create an abstraction (e.g. as an interface) of CustomerReqContract and implement the logic against this abstraction (used also by vendors etc.) instead of a particular implementation (CustomerReqContract).

  • Ferhat.S Profile Picture
    238 on at

    Hey,

    If i had to write like that i would like to use inheritnce insted of interfaces.

    So your party class will be main one and :

    class Party
    {
        public Party constructor(CustomerReqContract _custDetails)
        {
            switch(_custDetails.Customer().DirPartyType())
            {
                case DirPartyType::Organization:
                    return new OrganizationParty();
                    break;
                case DirPartyType::Person :
                     return new PersonParty();
                     break;
                default:
                    // handle this state :)
            }
        }
        
        public DirPartyBaseEntity createParty(Object _personDetailsContract)
        {
            
            // fill the common areas here.
    
            return dirPartyBaseEntity;
        }
        
    }

    other classes like

    class OrganizationParty extends Party
    {
        public DirPartyBaseEntity createParty(Object _personDetailsContract)
        {
            DirPartyBaseEntity entitiy;
            entity = next createParty(Object _personDetailsContract);
            
            // and fill orgnaization stuff here,
            return entitiy;
        }
    }

    Sorry if i did some syntax mistakes.

  • Ferhat.S Profile Picture
    238 on at

    Also if you want to save your CustomerReqContract object later on just put it on party object parameters and write parm method.

    like

    class Party
    {
        public CustomerReqContract localReqContaract;
        
        public Party constructor(CustomerReqContract _custDetails)
        {
            switch(_custDetails.Customer().DirPartyType())
            {
                case DirPartyType::Organization:
                    return new OrganizationParty();
                    break;
                case DirPartyType::Person :
                     return new PersonParty();
                     break;
                default:
                    // handle this state :)
            }
        }
        
        public DirPartyBaseEntity createParty(Object _personDetailsContract)
        {
            
            // fill the common areas here.
    
            return dirPartyBaseEntity;
        }
        public CustomerReqContract parmReqContract(CustomerReqContract _reqContract)
        {
            localReqContaract = _reqContract;
            return localReqContaract;
        }
        
    }

  • D365FO user Profile Picture
    465 on at

    Hi Martin,

    How to create an interface with contract classes?  

    [DataContractAttribute]
    public interface IPartyReqContract
    {
    
        [DataMemberAttribute]
        public PostalAddressExtendedContract PostalAddress(PostalAddressExtendedContract _postalAddress = postalAddress)
        {
            postalAddress = _postalAddress;
            return postalAddress;
        }
    
    
        [DataMemberAttribute]
        public ElectronicAddressContract ElectronicAddress(ElectronicAddressContract _electronicAddress = electronicAddress)
        {
            electronicAddress = _electronicAddress;
            return electronicAddress;
        }
    
    }

    Hi Ferhat, i don't like the idea to keep using objects

  • Martin Dráb Profile Picture
    237,965 Most Valuable Professional on at

    You shouldn't try to apply DataContract/DataMember attribues to an interface. Keep them in in the data contract class, just let the data contract class implement an interface with the common logic.

    Also note that I talked about personDetails() and orgDetails() methods. You code is about something else (you have no personDetails() and orgDetails() methods there).

  • D365FO user Profile Picture
    465 on at

    Hi Martin,

    but the customerReqContract is a data contract class and you asked me to do an interface for this one

    so the customerReqContract has data like OrgDetails, personDetails, postalAddress, electronic address etc... and i think all of those are shared with all parties.

    so how do you want me to create an interface from a data contract attribute? i didn't get it and what should the logic be

  • Suggested answer
    Martin Dráb Profile Picture
    237,965 Most Valuable Professional on at

    Hmm, I thought you knew what an interface is and how to use, but I'm not sure anymore.

    If you want to CustomerReqContract to implement an interface, it's definition will look like this:

    [DataContract]
    class CustomerReqContract implements YourCommonInterface

    The interface will contain declarations of methods that will be contained all contracts and that you want to use in a polymorphic way.

    You may add more methods than just personDetails() and orgDetails(), but that's off-topic. Only these two are needed for the scenario you asked about.

  • D365FO user Profile Picture
    465 on at

    Hi Martin,

    I did this

    public interface IPartyReqContract
    {
        public PersonDetailsContract PersonDetails(PersonDetailsContract personDetails)
        {
        }
    
        public OrganizationDetailsContract OrgDetails(OrganizationDetailsContract orgDetails)
        {
        }
    
        }
    
    }


    [DataContractAttribute]
    class CustomerReqContract  implements IPartyReqContract
    {
        [DataMemberAttribute]
        public PersonDetailsContract PersonDetails(PersonDetailsContract _personDetails = personDetails)
        {
            personDetails = _personDetails;
            return personDetails;
        }
        
        [DataMemberAttribute]
        public OrganizationDetailsContract OrgDetails(OrganizationDetailsContract _orgDetails = orgDetails)
        {
            orgDetails = _orgDetails;
            return orgDetails;
        }
    }


    but now what do you want me to do in the following 5 classes:

    class CreateCustomerService
    {
        public CustomerResContract createCustomerDetails(CustomerReqContract _custDetails)
        {
            //logic
            public PartyNumber createCustomerParty(CustomerReqContract _custDetails)
            {
                DictEnum dictEnum = new DictEnum(enumNum(DirPartyType));
                IPartyCreator partyCreator = PartyCreatorFactory::createParty(dictEnum.symbol2Value(_custDetails.Customer().DirPartyType()));
                if(partyCreator is PersonPartyCreator)
                {
                    return partyCreator.createParty(_custDetails.PersonDetails()).PartyNumber;
                }
                else
                {
        
                    return partyCreator.createParty(_custDetails.OrgDetails()).PartyNumber;
                }
            }
            
            //logic
            
            public PartyNumber createCustomerContactPersonParty(ContactPersonContract _contactPerson)
            {
                DictEnum dictEnum = new DictEnum(enumNum(DirPartyType));
                IPartyCreator partyCreator = PartyCreatorFactory::createParty(DirPartyType::Person);
        
                return partyCreator.createParty(_contactPerson.PersonDetails()).PartyNumber;
        
            }
        }
    
    }


    class PartyCreatorFactory
    {
    
        public static IPartyCreator createParty(DirPartyType _dirPartyType)
        {
            if(_dirPartyType == DirPartyType::Person)
            {
                return new PersonPartyCreator();
            }
            else if(_dirPartyType == DirPartyType::Organization)
            {
                return new OrganizationPartyCreator();
            }
            else
            {
                throw error('Invalid DirPartyType');
            }
        }
    


    public interface IPartyCreator
    {
    
        public DirPartyBaseEntity createParty(Object _partyDetails)
        {
        }
    
    }


    class PersonPartyCreator implements IPartyCreator
    {
    
        public DirPartyBaseEntity createParty(Object _personDetailsContract)
        {
            DirPartyBaseEntity dirPartyBaseEntity;
            if(_personDetailsContract is PersonDetailsContract)
            {
                PersonDetailsContract custPersonDetails = _personDetailsContract;
    
                if(custPersonDetails)
                {
                    //create Customer details based on DirPartyType which is Person
                    dirPartyBaseEntity.initValue();
                    dirPartyBaseEntity.PartyType               = enum2Str(DirPartyType::Person);
                    dirPartyBaseEntity.PersonFirstName         = custPersonDetails.FirstName();
                    dirPartyBaseEntity.PersonMiddleName        = custPersonDetails.MiddleName();
                    dirPartyBaseEntity.PersonLastName          = custPersonDetails.LastName();
                    dirPartyBaseEntity.PersonPersonalTitle     = custPersonDetails.PersonalTitle();
    
                    RecId NameSequenceRecId = DirNameSequence::find(custPersonDetails.NameSequence()).RecId;
                    if(NameSequenceRecId != 0)
                    {
                        dirPartyBaseEntity.NameSequence = NameSequenceRecId;
                    }
                    if(custPersonDetails.BirthDate())
                    {
                        dirPartyBaseEntity.PersonBirthDay   = custPersonDetails.BirthDate().BirthDay();
                        dirPartyBaseEntity.PersonBirthMonth = custPersonDetails.BirthDate().BirthMonth();
                        dirPartyBaseEntity.PersonBirthYear  = custPersonDetails.BirthDate().BirthYear();
                    }
    
                    dirPartyBaseEntity.insert();
                }
            }
    
            return dirPartyBaseEntity;
        }
    
    }


    class OrganizationPartyCreator implements IPartyCreator
    {
    
        public DirPartyBaseEntity createParty(Object _orgDetailsContract)
        {
            DirPartyBaseEntity dirPartyBaseEntity;
    
            if(_orgDetailsContract is OrganizationDetailsContract)
            {
                OrganizationDetailsContract orgDetails = _orgDetailsContract;
    
                if(orgDetails)
                {
                    dirPartyBaseEntity.Name = orgDetails.PartyName();
                    dirPartyBaseEntity.PartyType = enum2Str(DirPartyType::Organization);
                    dirPartyBaseEntity.OrganizationNumber = orgDetails.OrgNumber();
                    dirPartyBaseEntity.OrganizationNumOfEmployees = orgDetails.NumberOfEmployees();
    
                    dirPartyBaseEntity.insert();
                }
            }
            
            return dirPartyBaseEntity;
        }
    
    }


Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 551 Most Valuable Professional

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 450 Super User 2025 Season 2

#3
BillurSamdancioglu Profile Picture

BillurSamdancioglu 278 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans