You need metadata
In order for a user to be able to add custom card types that may or may not have specific business rules or behavior, the user must be able to specify whether the behavior applies, and you need to be able to store it.
So you will need a metadata table, sort of like this:
CREATE TABLE CardTypes
(
Code Char(4),
Description VarChar(40),
RequiresFooProcesser bit
)
You would then initialize the table with your default card types. In this example, the Visa card requires the FooProcessor, but the Amex doesn't.
INSERT CardTypes ( 'VISA','Standard VISA card', 1 )
INSERT CardTypes ( 'AMEX','Standard American Express', 0 )
Handling use cases dynamically
When a user enters a new card type, you expose a UI that lets them specify the card type code and tick a checkbox telling the application whether the magic FooProcessor is required. You then store the card type code, the description, and the flag that tells the system whether the FooProcessor is required. When you're done, the metadata for the user's new card type looks exactly like the metadata for the default card types.
When a user enters a new card, the UI asks the user to select the card type from a list populated from the metadata table. You then store the cardtype's Code
with the card (as a foreign key) so that you know which metadata applies to the card that the user just entered.
When it is time to process the card, your code needs to check the flag.
So as a developer you would change this code:
//Old
if (card.Type == CardType.Visa) //Check enum
{
RunFooProcessor(card);
}
...to this code...
//New
var cardType = dbContext.CardTypes.Single( c => c.Code == card.Type );
if (cardType.RequiresFooProcessor) //Check flag
{
RunFooProcessor(card);
}
This elimlinates the need to check for specific enum values or specific card types; instead, you check for a flag that is assigned to the card type at run time.
The metadata can be useful for other purposes as well. For example, if card types are restricted by BIN, you can ask the user for a list of valid BINs and store them as additional metadata, and develop your system to validate card numbers correctly without actually knowing if something is a Visa, Amex, or whatever.
The point of this effort is to make the system agnostic with respect to card type and instead design it with generic concepts that can be associated with card types at run time.