Reputation: 15050
I have a question of good practices and how to organize the code. I have a model built in Angular 4+ project. The model has many variables which are passed through the constructor but has also getters and setters:
export class SomeModel {
private variableOne: string;
private variableTwo: string;
private variableThree: string;
private variableFour: number;
private variableFive: number;
private variableSix: string;
private variableSeven: string;
private variableEight: number;
private variableNine: number;
private variableTen: string;
private variableEleven: string;
private variableTwelve: string;
private variableThirteen: string;
private variableFourteen: string;
constructor (variableOne: string, variableTwo: string, variableThree: string, variableFour: number, variableFive: number, variableSix: string, variableSeven: string, variableEight: number, variableNine: number, variableTen: string, variableEleven: string, variableTwelve: string, variableThirteen: string, variableFourteen: string) {
this.variableOne = variableOne;
this.variableTwo = variableTwo;
this.variableThree = variableThree;
this.variableFour = variableFour;
this.variableFive = variableFive;
this.variableSix = variableSix;
this.variableSeven = variableSeven;
this.variableEight = variableEight;
this.variableNine = variableNine;
this.variableTen = variableTen;
this.variableEleven = variableEleven;
this.variableTwelve = variableTwelve;
this.variableThirteen = variableThirteen;
this.variableFourteen = variableFourteen;
}
// setters
public setVariableOne(variableOne: string) {
this.variableOne = variableOne;
}
public setVariableTwo(variableTwo: string) {
this.variableTwo = variableTwo;
}
public setVariableThree(variableThree: string) {
this.variableThree = variableThree;
}
public setVariableFour(variableFour: number) {
this.variableFour = variableFour;
}
public setVariableFive(variableFive: number) {
this.variableFive = variableFive;
}
public setVariableSix(variableSix: string) {
this.variableSix = variableSix;
}
public setVariableSeven(variableSeven: string) {
this.variableSeven = variableSeven;
}
public setVariableEight(variableEight: number) {
this.variableEight = variableEight;
}
public setVariableNine(variableNine: number) {
this.variableNine = variableNine;
}
public setVariableTen(variableTen: string) {
this.variableTen = variableTen;
}
public setVariableEleven(variableEleven: string) {
this.variableEleven = variableEleven;
}
public setVariableTwelve(variableTwelve: string) {
this.variableTwelve = variableTwelve;
}
public setVariableThirteen(variableThirteen: string) {
this.variableThirteen = variableThirteen;
}
public setVariableFourteen(variableFourteen: string) {
this.variableFourteen = variableFourteen;
}
// getters
public getVariableOne() {
return this.variableOne;
}
public getVariableTwo() {
return this.variableTwo;
}
public getVariableThree() {
return this.variableThree;
}
public getVariableFour() {
return this.variableFour;
}
public getVariableFive() {
return this.variableFive;
}
public getVariableSix() {
return this.variableSix;
}
public getVariableSeven() {
return this.variableSeven;
}
public getVariableEight() {
return this.variableEight;
}
public getVariableNine() {
return this.variableNine;
}
public getVariableTen() {
return this.variableTen;
}
public getVariableEleven() {
return this.variableEleven;
}
public getVariableTwelve() {
return this.variableTwelve;
}
public getVariableThirteen() {
return this.variableThirteen;
}
public getVariableFourteen(){
return this.variableFourteen;
}
}
Now let's use this model in someMethod()
in our project component:
someMethod () {
this.someService.getDataFromServer().subscribe(response => {
let myJsonObject = response.json();
let myJsonArray = myJsonObject._embedded;
for (let i = 0; i < myJsonArray.length; i++) {
let currentObject = myJsonArray[i];
let myNewObject = new SomeModel(currentObject.variableOne, currentObject.variableTwo, currentObject.variableThree, currentObject.variableFour, currentObject.variableFive, currentObject.variableSix, currentObject.variableSeven, currentObject.variableEight, currentObject.variableNine, currentObject.variableTen, currentObject.variableEleven, currentObject.variableTwelve, currentObject.variableThirteen, currentObject.variableFourteen);
this.objectsList.push(myNewObject);
}
});
}
Too long and unreadable, isn't it? Sure we can use enter and move every single variable in the constructor to the new line. But since we can use setters, should we use them instead (of course all variables need to be removed from the model's contractor)?
someMethod () {
this.someService.getDataFromServer().subscribe(response => {
let myJsonObject = response.json();
let myJsonArray = myJsonObject._embedded;
for (let i = 0; i < myJsonArray.length; i++) {
let currentObject = myJsonArray[i];
let myNewObject = new SomeModel();
myNewObject.setVariableOne(currentObject.variableOne);
myNewObject.setVariableTwo(currentObject.variableTwo);
myNewObject.setVariableThree(currentObject.variableThree);
myNewObject.setVariableFour(currentObject.variableFour);
myNewObject.setVariableFive(currentObject.variableFive);
myNewObject.setVariableSix(currentObject.variableSix);
myNewObject.setVariableSeven(currentObject.variableSeven);
myNewObject.setVariableEight(currentObject.variableEight);
myNewObject.setVariableNine(currentObject.variableNine);
myNewObject.setVariableTen(currentObject.variableTen);
myNewObject.setVariableEleven(currentObject.variableEleven);
myNewObject.setVariableTwelve(currentObject.variableTwelve);
myNewObject.setVariableThirteen(currentObject.variableThirteen);
myNewObject.setVariableFourteen(currentObject.variableFourteen);
this.objectsList.push(myNewObject);
}
});
}
What advantage gives approach presented above, except the code is more readable of course? Also, does it make sense to pass partially variables through model's constructor and by setters?
Upvotes: 0
Views: 63
Reputation: 2192
This is a common practice, I use in several projects. First I create a TypeScript Interface (BaseInterface for example) for all models:
export interface BaseInterface {
/**
* Build the object attributes
* @param {any} attrs
*/
build(attrs: any): void;
/**
* Return a JSON object representation of the object
* @return {any}
*/
toJson(): any;}
Then create your model
import { BaseInterface } from './model.interface';
export class Account implements BaseInterface {
id: number;
name: string;
/* add attributes */
/**
* Class constructor
* @param {any = null} attrs
*/
constructor(attrs: any = null) {
if (attrs) {
this.build(attrs);
}
}
/**
* Build the object attributes
* @param {any} attrs
*/
build(attrs: any): void {
this.id = attrs.id;
this.name = attrs.name;
}
/**
* Return a JSON object representation of the object
* @return {any}
*/
toJson(): any {
return JSON.stringify({
id: this.id,
name: this.name
});
}}
Create sample service retrieving all accounts for example:
export class AccountService{
constructor(private http: HttpClient) {
}
all(): Observable<Account[]> {
return this.http
.get('http://fake-server.com/accounts', {})
.map((data: any) => data.map(account => new Account(account)) );
}}
In this your component, you can write some method
accounts: Array<Account> = [];
private loadAccounts() {
this.accountService.all().subscribe(
(data) => {
this.accounts = this.data;
},
(err) => {
console.error(err);
}
);
}
You don't need several accessors and mutators for your models. You don't need a loop in your methods for building your models; Hope I help!
Upvotes: 2
Reputation: 1548
It's hard to answer the question without knowing what the properties actually are. But are there advantages in the two different ways? There might be.
Setters allow you to keep your constructor smaller. But you would need default values, in case your class is instantiated without setting all the properties it might need. This might actually be better, if those properties are optional, or tend to always default to the same thing. Setters also make it easier to trap any updates to properties for debugging, or to add validation.
Constructor force all properties to be set, which might be better depending on the scenario.
But generally, a class with that many required properties seems like a code smell to me. It may be better to break your code down into a series of smaller classes, which are composed by a higher class.
For example, if your actual class was a Person, with properties
firstname
lastname
age
addressline1
addressline2
town
country
zipcode
holidaydestinationcountry
holidaystartdate
holidayenddate
It could make more sense to create an Address class, and a Holiday class, and have your Person class take less constructor arguments
new Person(firstname,lastname,address,holiday)
You would still need to create the address instance, and holiday instance, and set the properties on those, but your code would be much easier to read, and maintain.
Upvotes: 1
Reputation: 4451
I also had this issue and resolved it in the following way:
Assuming you get your model data from JSON, define the method fromJSON()
in your model class, or extract it to a super class and extend from it.
fromJSON(json) {
for (let propName in json)
this[propName] = json[propName];
return this;
}
What does it? It assigns for all properties found in the JSON Object the property in this model class and sets the value.
To be used like this: SomeModel model = new SomeModel().fromJSON(jsonData);
Upvotes: 1