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.

2
  • 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. Commented May 14, 2018 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
    Commented May 17, 2018 at 9:56

2 Answers 2

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.

5
  • 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.
    – Janilson
    Commented May 11, 2018 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. Commented May 11, 2018 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.
    – Janilson
    Commented May 12, 2018 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. Commented May 12, 2018 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.
    – GHP
    Commented May 18, 2018 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();
    }
}
0

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