patternjavaMinor
Business logic in service method
Viewed 0 times
servicebusinesslogicmethod
Problem
I'm currently writing a small asset tracking system.
The implementation should meet the following requirements:
The system; scans the transfers every 15 minutes. If the transfer is
accepted by the receiver by the specified transfer time, realizes the
transfer. When a transfer is realized, assets are assigned to the
receiver as of transfer time; if the transfer is permanent, actual
owner is changed also.
The system; If the transfer operation is not accepted by the receiver
by the specified transfer time; cancels the transfer.
Above requirement is dependent on this straight-forward requirement (UI related parts omitted):
Transferring user; When a new transfer is started,
[...]
and specifies
The implementation:
```
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Service
public class TransferServiceImpl implements TransferService {
private Repository repository;
private Repository assetRepository;
@Override
public void informTransferTimeIsUp(long transferId) {
Transfer transfer = repository.get(transferId);
transfer.informTransferTimeIsUp();
if (transfer.isRealized()) {
Set transferredAssets = assetRepository.getAll(transfer.getTransferredAssets());
for (Asset asset : transferredAssets) {
if (TransferType.TEMPORARY.equals(transfer.getTransferType())) {
asset.transferTemporarily(transfer.getReceiver());
} else {
asset.transferPermanently(transfer.getReceiver());
}
assetRepository.update(asset);
}
}
reposi
The implementation should meet the following requirements:
The system; scans the transfers every 15 minutes. If the transfer is
accepted by the receiver by the specified transfer time, realizes the
transfer. When a transfer is realized, assets are assigned to the
receiver as of transfer time; if the transfer is permanent, actual
owner is changed also.
The system; If the transfer operation is not accepted by the receiver
by the specified transfer time; cancels the transfer.
Above requirement is dependent on this straight-forward requirement (UI related parts omitted):
Transferring user; When a new transfer is started,
[...]
and specifies
- the time when the transfer will be realized
- whether the transfer is temporary or permanent
- assets to be transferred
- the receiver
- [... and saves ....]
The implementation:
```
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Service
public class TransferServiceImpl implements TransferService {
private Repository repository;
private Repository assetRepository;
@Override
public void informTransferTimeIsUp(long transferId) {
Transfer transfer = repository.get(transferId);
transfer.informTransferTimeIsUp();
if (transfer.isRealized()) {
Set transferredAssets = assetRepository.getAll(transfer.getTransferredAssets());
for (Asset asset : transferredAssets) {
if (TransferType.TEMPORARY.equals(transfer.getTransferType())) {
asset.transferTemporarily(transfer.getReceiver());
} else {
asset.transferPermanently(transfer.getReceiver());
}
assetRepository.update(asset);
}
}
reposi
Solution
Set transferredAssets = assetRepository.getAll(transfer.getTransferredAssets());
for (Asset asset : transferredAssets) { ... }Since the transfer isn't done yet, and also to prevent ambiguity post-transfer, may I suggest renaming the method to
getAssets()? You can also inline the call:for (Asset asset : assetRepository.getAll(transfer.getTransferredAssets())) { ... }Two minor improvements I can suggest for the snippet below:
- It's safe to compare
enums by==.
- Have a
transfer(TransferType, long)method inAssetso that the toggling is done withinAsset: callers only need to supply theTransferTypevalue.
if (TransferType.TEMPORARY.equals(transfer.getTransferType())) {
asset.transferTemporarily(transfer.getReceiver());
} else {
asset.transferPermanently(transfer.getReceiver());
}Since the use of
realized and cancelled are just opposites of each other, you may want to consider having just a single boolean field, to keep the implementation simpler.if (accepted) {
this.realized = true;
} else {
this.cancelled = true;
}In
Asset:public void transferTemporarily(long receiverId) {
this.currentOwnerId = receiverId;
this.unblockIfBlocked();
}
public void transferPermanently(long receiverId) {
this.actualOwnerId = receiverId;
this.currentOwnerId = receiverId;
this.unblockIfBlocked();
}This can be slightly simplified as:
public void transferTemporarily(long receiverId) {
this.currentOwnerId = receiverId;
this.unblockIfBlocked();
}
public void transferPermanently(long receiverId) {
transferTemporarily(receiverId);
this.actualOwnerId = receiverId;
}Alternatively, if reading
temporarily inside a permanent method is slightly confusing, have a new method setCurrentOwnerAndUnblock() to do that instead...Code Snippets
Set<Asset> transferredAssets = assetRepository.getAll(transfer.getTransferredAssets());
for (Asset asset : transferredAssets) { ... }for (Asset asset : assetRepository.getAll(transfer.getTransferredAssets())) { ... }if (TransferType.TEMPORARY.equals(transfer.getTransferType())) {
asset.transferTemporarily(transfer.getReceiver());
} else {
asset.transferPermanently(transfer.getReceiver());
}if (accepted) {
this.realized = true;
} else {
this.cancelled = true;
}public void transferTemporarily(long receiverId) {
this.currentOwnerId = receiverId;
this.unblockIfBlocked();
}
public void transferPermanently(long receiverId) {
this.actualOwnerId = receiverId;
this.currentOwnerId = receiverId;
this.unblockIfBlocked();
}Context
StackExchange Code Review Q#88763, answer score: 2
Revisions (0)
No revisions yet.