Reputation: 137
To keep things simple: Let's say you have an entity relationship diagram (ERD) with the following tables:
Survey
: Id, name, questions Question
: Id, text, surveyIn this case a Survey
has one or more Questions
and a Question
only belongs to one Survey
.
My question is, can I recreate this architecture using classes only without any persistency layer like Realm or Core data? This is a simple demonstration of what I mean:
struct Survey {
var id: Int
var name: String
var questions: [Question] // 1 or more questions
}
struct Question {
var id: Int
var text: String
var survey: Survey // belongs to only one survey
}
I tried this approach but obviously the following code won't work due to the one to many relationship:
let survey = Survey(id: 0, name: "First survey", questions: [
Question(id: survey.id, text: "Whats your name", survey: survey) // This is not possible.
])
More background: I want to create a survey application. The architecture of the app is difficult to design since the survey will support multiple types of questions (multiple choice, open questions, yes/no questions and so on). Doing an online search I found out there are a few ERD designs for a survey like this one. The problem is that this ERD design is for databases .. but I don't want to create a database for now. I assume however that architecturally the design can be represented using classes. So the question is how?
Upvotes: 1
Views: 110
Reputation: 73456
ERD is rooted in relational algebra which was made primarily for relational database modelling. You may nevertheless perfectly use it for modelling an architecture that does not use relational databases, and even without any persistence.
But ERD was invented in a time where OOP was quite exotic. Several extended ERD variants (EERD) exist, each trying to address inheritance and specialisation in its own way, but with a weak semantic and no authoritative standard.
A better approach would be to model your design with an UML class-diagram, with full support for OOP and wiki may look like:
Indeed, the intent to support "multiple types of questions" strongly suggest to use some specialisation (sub-types) of Question
since the content and behavior of multiple choice is very different from an open question. Inheritance would then allow to apply the Open Closed Principle, i.e. easily add new types of questions without changing the rest of the code.
Consequence on your code: Question
should not be a struct
but a class
or a protocol.
Another point is to clarify why the Question
would need to know about the Survey
. I am not sure, and therefore I used a unidirectional navigation arrow. Indeed, one could easily imagine the same question being used in several surveys.
If you need it, your design is problematic, because it is difficult to initialise a survey with questions as your code does, and moreover, nothing would prevent inconsistencies, with a question referring to another survey than the one it is included in.
To solve this, consider, either a design without reference back, or at least to create the Survey and add questions in two steps: a method instead of directly modifying the array could enforce consistency. Alternatively, you could consider some creative use of didSet
Upvotes: 0
Reputation: 21154
You have dependencies between these two objects since initializer for both structs expect other to be created before, this is just a fault in design. You can tackle this kind of dependencies by using optionals or implicitly unwrapped optional (which is not safe).
Here is one obvious way to solve it,
struct Survey {
var id: Int
var name: String
var questions: [Question]! // 1 or more questions
init(id: Int, name: String) {
self.id = id
self.name = name
}
}
struct Question {
var id: Int
var text: String
var survey: Survey // belongs to only one survey
}
So, instead of passing object inside initializer, you could create one object without the need to create other struct and simply use assignment.
var survey = Survey(id: 0, name: "First survey")
survey.questions = [
Question(id: survey.id, text: "Whats your name", survey:survey) // This is not possible.
]
Upvotes: 0