Fun fact, if you adopt the latter pattern, you can implement a library like Selector to do the filtering for you.
public with sharing class AccountService
{
public static Select.Filter isFlagged()
{
return Select.Field.isEqual(Account.Some_Flag__c, true);
}
public static void validateFlaggedAccounts(List<Account> flaggedAccounts)
{
for (Account flaggedAccount : flaggedAccounts)
flaggedAccount.addError('message');
}
}
Then in your trigger you can just do:
AccountServices.validateFlaggedAccounts(
AccountServices.isFlagged().filter(trigger.new, trigger.oldMap)
);
One huge advantage of this pattern is it's way easier to test. You can test the positive/negative filter cases very easily, then test your action completely independently. Separation of concerns, ftw!
static final Integer RECORD_COUNT = Limits.getLimitQueries() + 1;
static testMethod void testIsFlagged_Positive()
{
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < RECORD_COUNT; i++)
accounts.add(new Account(Some_Flag__c=true));
Test.startTest();
List<Account> results = AccountService.isFlagged().filter(accounts);
Test.stopTest();
system.assertEquals(RECORD_COUNT, results.size(), 'message');
}
static testMethod void testIsFlagged_Negative()
{
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < RECORD_COUNT; i++)
accounts.add(new Account(Some_Flag__c=false));
Test.startTest();
List<Account> results = AccountService.isFlagged().filter(accounts);
Test.stopTest();
system.assertEquals(0, results.size(), 'message');
}