Fun fact, if you adopt the latter pattern, you can implement a library like [Selector](https://github.com/bluewolf-beyond/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');
    }