cconnected.
Understand the pattern. Find your own way.Find your starting point
Your learning feed/Idea 164 of 218
Ideas this builds on
Low-level design164 / 218

Choose how an object is built

Picture

Configuration chooses flat or per-item delivery. A small factory turns that choice into a usable pricing object, so every caller does not repeat construction branches.

Predict

How is the factory’s responsibility different from the pricing strategy’s?

Walk through the small example

The factory chooses and constructs a collaborator. The strategy computes a fee when used. One can create the other without being the same pattern.

Mental model and complete Python solution

Both concrete policy classes expose fee(count). make_fee_policy validates configuration and returns the corresponding object. Unknown names fail explicitly rather than quietly charging under an unintended rule. The factory lives at the construction boundary; business operations can use the resulting interface without repeatedly reading configuration. This is a simple factory, not a claim to implement every Factory Method or Abstract Factory variation.

What the function promises: Policy kind is flat or per_item, with a nonnegative integer amount. fee requires a nonnegative integer count. Values are minor currency units.

class FlatFee:
    def __init__(self, amount):
        self.amount = amount

    def fee(self, count):
        if type(count) is not int or count < 0:
            raise ValueError("Invalid count")
        return self.amount

class PerItemFee:
    def __init__(self, amount):
        self.amount = amount

    def fee(self, count):
        if type(count) is not int or count < 0:
            raise ValueError("Invalid count")
        return self.amount * count

def make_fee_policy(kind, amount):
    if type(amount) is not int or amount < 0:
        raise ValueError("Invalid amount")
    constructors = {"flat": FlatFee, "per_item": PerItemFee}
    if kind not in constructors:
        raise ValueError("Unknown fee policy")
    return constructors[kind](amount)

assert make_fee_policy("flat", 50).fee(3) == 50
assert make_fee_policy("per_item", 10).fee(3) == 30
try:
    make_fee_policy("mystery", 10)
except ValueError:
    pass
else:
    raise AssertionError("Unknown policy was not rejected")

Work and storage: Expected O(1) dispatch and construction for this fixed registry. A factory does not inherently reduce algorithmic work.

When to recognize it: Callers need a working policy without repeating construction choices everywhere.

Check before applying it: Reject unknown configuration. A factory chooses construction; it does not automatically make every later behavior interchangeable.

Change one rule

Only the amount changes, and all policies calculate amount×count. Do we need separate classes per price?

See what changes

No. Parameterize one policy object. Classes represent meaningful behavioral differences, not every configuration value.

Connect

Swap the rule, not the whole feature: A factory can build a strategy; these patterns answer different questions.

Agree on a small promise: Constructed objects still need the promised interface.