I would like to know if I’m going about this the wrong way…
My intention is to create a set of classes that interact with my server-side API to provide pseudo ORM functionality. For example…
Bootstrap <> User <> API <> HTTP
Mapper <> Map <> API <> HTTP
- Really the only class that should be a MonoBehaviour is the one at the top of each chain.
- That would then “new” up a User/Map class.
- These would contain properties and methods that specifically relate to those API services
- The API class would be more generic, handling the specific properties of the above classes, url serialization and executing through…
- The HTTP class, where the final http request is conducted through UnityWebRequest
This would conform to the single responsibility pattern. The issue I’m having is the web request needs to be in a coroutine and as the top class needs to be aware of the response content I need to pass it up the classes in a horrible chain of IEnumerators and yield returns. Using the top answer here… How do I return a value from a coroutine? - Questions & Answers - Unity Discussions I’ve attempted to implement the below.
An example…
- Loader Class creates new user and calls getUser() on it
- User class creates an API object and passes the service locator “user” to the get() method
- API class serializes “user”, domain and SystemInfo.deviceUniqueIdentifier to create url “http://example.com/user/abcd1234”
- API class calls HTTP class GET with url
- HTTP class executes UnityWebRequest.Get(url)
- API class should wait for response on HTTP
- User class should wait for response on API
- Loader class should wait for response on User
- Loader class does something with response
Needless to say, I don’t think posting the actual code is worthwhile as it doesn’t work, besides I think it’s quite messy even if I did get the data handoff correct. I suppose I could add these all to their own gameobjects as MonoBehaviours and check for a response every “Update” but that also seems incorrect. Same goes for some sort of singleton pattern, as ideally I’d like to quickly instantiate an object that handles a request/response when required. Of course, perhaps I shouldn’t be saying what is “incorrect”, I’m open to any thoughts.
- Should I be trying to implement this as above?
- If so, can you help me pass the data back up to the Loader class?
- If not, how can I implement this without duplicating code and without creating a god class?
This is a lot about design patterns and the way I should be laying out my scripts really… I feel that by understanding this I’ll be in good stead with planning out my objects and classes in the future.
Thank you very much.
Update
This was also posted on the forums… http://forum.unity3d.com/threads/game-script-structure-design-pattern-and-asynchronous-methods.413314/
The main difference is I showed an example of what I would have done if this were a synchronous job…
using UnityEngine;
using Project.API;
namespace Project
{
public class Loader : MonoBehaviour
{
void Start () {
User User = new User();
if (User.id != null) {
Debug.Log("User found");
}
}
}
}
namespace Project.API
{
public class User
{
private string service = "user";
private API api;
public int? id = null;
public User() {
api = new API();
object user = api.get(service);
id = user.id;
}
}
}
-
using UnityEngine;
using Project.HTTP;namespace Project.API
{
public class API
{private string domain = "http://example.com/"; private Connection connection; private string device_id; public API() { connection = new Connection(); device_id = SystemInfo.deviceUniqueIdentifier; } public object get(string service, string[] parameters = null) { return connection.get(domain + service + "/" + device_id + serialize(parameters)); } private string serialize(string[] parameters) { string serialized_parameters = "/"; if (parameters != null) { for (int i = 0; i < parameters.Length; i++) { serialized_parameters += parameters *+ "/";*
}
}
return serialized_parameters;
}
}
}
-
using webRequest; // Fake synchronous web request library
namespace Project.HTTP
{
public class Connection
{
public object get(string url) {
return www.get(url);
return new object();
}
}
}