I have an OO design concern. Let's say my models as following:
class Account {}
class LocalAccount extends Account {}
class SocialAccount extends Account {}
These Account entities are persisted and I could retrieve them (or do more operations on them) through a typical Repository. Let's say I have the following interface:
AccountRepository:
interface AccountRepository {
getAll(): Array<Account> ;
}
And I have some use-cases where I need to work with Accounts where I basically would inject the AccountRepository, eg.
class FooUseCase {
private AccountRepository accountRepository;
constructor(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
public execute(): void {
// Use case logic where I would call accountRepository.getAll()
}
}
And at this point is where I am actually struggling. After some analysis, I thought about having specific AccountRepository implementations:
LocalAccountRepository:
class LocalAccountRepository implements AccountRepository {
public getAll(): Array<LocalAccount> { /* implementation */ }
}
SocialAccountRepository:
class SocialAccountRepository implements AccountRepository {
public getAll(): Array<SocialAccount> { /* implementation */ }
}
This would be alright, as far as a use-case would just need to work with LocalAccount or SocialAccount entities. But, what would happen if I would just needed to work with Account entities?
I feel I could implement an AccountRepository, that could just return a list of Accounts, but I feel that at the public getAll(): Array<Account> I would somehow have to add some kind of switch/if-else statement to be able to create each type of Account object... Which I think might violate some design principles (every time a new Account is added would have to extend the if-else, etc.).
AccountRepositoryImpl:
class AccountRepositoryImpl implements AccountRepository {
public getAll(): Array<Account> {
// Database access, query, etc.
// results iteration
let account: Account;
if (result.type === AccountType.Local) {
account = new LocalAccount(/* params */);
} else if (result.type === AccountType.Social) {
account = new SocialAccount(/* params */);
}
accounts.add(account);
// iteration end
return accounts;
}
}
Any design improvement suggestions to my issues?
AccountRepository.getAllto just merge data fromSocialAccountRepository.getAllandLocalAccountRepository.getAll, because they are separate, unrelated queries. (They could even be run in parallel.)