1

I have a program that communicates with an API to get information on different organizations, so I have an Organization class and an ApiCall class which are both closely related. As the API I'm using requires different tokens, url endpoints and authentifications to be used depending on the organization I'm trying to get data, I use a different instance of ApiCall for each instance of Organization (basically a 1-1 relationship).

So the first thing that comes to mind is to have an ApiCall instance as a property of Organization, however the api class has several methods that can alter or update data from the Organization class.

So there are many ways of implementing this. Personally I was considering 4 of them:

  1. A circular reference, where Organization holds an ApiCall instance as a property and ApiCall holds an Organization instance
  2. I could have ApiCall as a nested class inside Organization, however both classes are fairly sizeable (>300 lines) so I don't like the idea of mixing them. So maybe have Organization as a partial class where one file has the Organization methods implementation and the other file has the nested class (ApiCall) implementation?
  3. Have a static Dictionary shared across the program correlating the Organization and ApiCall instances
  4. Split Organization in 2 classes, OrgData and OrgActions, where OrgActions references ApiCall and OrgData and ApiCall references OrgData

I'm leaning towards alternatives 2 or 4 at the moment, but I was wondering what others would consider the better choice.

  • ApiCall sounds like an operation (a verb) and Organization sounds like a noun, so I would keep them separate, or make Organization a parameter or property of ApiCall, and remove references to ApiCall from Organization. – Frank Hileman May 14 '18 at 15:28
  • Is an Organization going to reuse its same Apicall? Or can the organization use these as one-time-use objects, i.e. new ApiCall(this).DoSomeWork()? Or does the ApiCall actually retain state/data for a functional purpose? – Flater May 17 '18 at 9:56
1

First get your responsabilities and names right. It looks to me this is what you have:

OrganizationInfo

This is just a data class, it knows nothing about any API or connection parameters.

ConnectionInfo

This holds parameters to establish the connection with the data source. It knows nothing about an API or organizations.

Connector

This has behavior. It knows how to connect to the data sources, using a ConnectionInfo object. It can on request deliver an OrganizationInfo object for a particular specified organization.

Fetcher

This knows the first three classes and retrieves all organization info records.

You have no circular references.

  • If you cut ConnectionInfo then that's essentially what I suggested in alternative 4: to split Organization into OrgData and OrgActions(that you call Fetcher). Any specific reason why you think ConnectionInfo is necessary? I don't see why things like security tokens, token expiration times or other similar data shouldn't be fields of the class making the requests to the API. – Lucas May 11 '18 at 20:04
  • @Lucas The class making the call is only interested in the org. info, it should not know about (have dependencies towards) technical details of the connection. Separation of concerns. – Martin Maat May 11 '18 at 20:32
  • 2
    That's like saying Person object should have a single field PersonData, and a PersonData class with info like name, age, and so on. If we go by that logic then all the classes on every program would be split into data classes and method classes that hold data classes as properties, which seems like completely overdoing it. Both Connector and Connectioninfo have the same concern, which is the connection, and it's almost certain that ConnectionInfo only interacts with the Connector without ever getting accessed by any other class of the program, so I still disagree these two should be separate. – Lucas May 12 '18 at 13:53
  • @Lucas A person does not have a different name every time it is interacted with. Your person data is very much hard-tied to a particular individual. A connector however connects to different sources depending on the connection info it gets passed. There is but one connector, it could even be static. It is the connection info that varies. – Martin Maat May 12 '18 at 14:29
  • @Lucas Separating data structures from behavior is perfectly valid and natural if you do it in the application from the start, rather than having some classes with behavior and some without. If you do not need stateful objects, then data structures + functions is often a simpler way of coding than normal OOP where data/behavior get blended. – Graham May 18 '18 at 18:32
-2

Your ApiCall should accept an Interface as a parameter.

In other words, you should have an ApiCall method that takes an IOrganization interface with different implementations

public interface IOrganization
{
    void CallOutToServer();
}

public class OrgType1 : IOrganization
{
    public void CallOutToServer()
    {
        // implement the callout logic here
    }
}

public class OrgType2 : IOrganization
{
    public void CallOutToServer()
    {
        // implement the callout logic here
    }
}

public class APiCall
{
    public void DoCallOut(IOrganization org)
    {
        org.CallOutToServer();
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.