Card 03/ 08
Facade Template in Python, Java and TypeScript
Three subsystem classes and one facade method that calls them in order.
The Facade template is the pattern in its pure form, with the participant names from the class diagram. The facade's one method calls three subsystem classes and passes the first result to the second, an ordering the facade holds so that clients do not have to. The steps add each participant in Python, and the tabs give the complete program in three languages, each with its output.
Building the template one participant at a time
Subsystem classes
Ordinary classes with their own methods, unaware of any facade.
class SubsystemA:
def prepare(self) -> str:
return "A prepared"
class SubsystemB:
def process(self, step: str) -> str:
return f"B processed after {step}"Facade
Holds the subsystem objects and calls them in order.
class Facade:
def operation(self) -> list[str]:
first = self._a.prepare()
return [first, self._b.process(first), self._c.finish()]Client
Calls the facade, and can still call a subsystem class.
client(Facade(SubsystemA(), SubsystemB(), SubsystemC()))
print(SubsystemC().finish(), "(called directly)")The complete template
class SubsystemA:
def prepare(self) -> str:
return "A prepared"
class SubsystemB:
def process(self, step: str) -> str:
return f"B processed after {step}"
class SubsystemC:
def finish(self) -> str:
return "C finished"
class Facade:
def __init__(self, a: SubsystemA, b: SubsystemB, c: SubsystemC) -> None:
self._a = a
self._b = b
self._c = c
def operation(self) -> list[str]:
first = self._a.prepare()
return [first, self._b.process(first), self._c.finish()]
def client(facade: Facade) -> None:
for line in facade.operation():
print(line)
client(Facade(SubsystemA(), SubsystemB(), SubsystemC()))
print(SubsystemC().finish(), "(called directly)")A prepared
B processed after A prepared
C finished
C finished (called directly)import java.util.List;
public class FaTemplate {
static void client(Facade facade) {
facade.operation().forEach(System.out::println);
}
public static void main(String[] args) {
client(new Facade(new SubsystemA(), new SubsystemB(), new SubsystemC()));
System.out.println(new SubsystemC().finish() + " (called directly)");
}
}
class SubsystemA {
String prepare() {
return "A prepared";
}
}
class SubsystemB {
String process(String step) {
return "B processed after " + step;
}
}
class SubsystemC {
String finish() {
return "C finished";
}
}
class Facade {
private final SubsystemA a;
private final SubsystemB b;
private final SubsystemC c;
Facade(SubsystemA a, SubsystemB b, SubsystemC c) {
this.a = a;
this.b = b;
this.c = c;
}
List<String> operation() {
String first = a.prepare();
return List.of(first, b.process(first), c.finish());
}
}A prepared
B processed after A prepared
C finished
C finished (called directly)class SubsystemA {
prepare(): string {
return "A prepared";
}
}
class SubsystemB {
process(step: string): string {
return `B processed after ${step}`;
}
}
class SubsystemC {
finish(): string {
return "C finished";
}
}
class Facade {
constructor(
private readonly a: SubsystemA,
private readonly b: SubsystemB,
private readonly c: SubsystemC,
) {}
operation(): string[] {
const first = this.a.prepare();
return [first, this.b.process(first), this.c.finish()];
}
}
function client(facade: Facade): void {
facade.operation().forEach((line) => console.log(line));
}
client(new Facade(new SubsystemA(), new SubsystemB(), new SubsystemC()));
console.log(new SubsystemC().finish(), "(called directly)");A prepared
B processed after A prepared
C finished
C finished (called directly)The first three lines of output come from one facade call; the client never learned that B needs A's result. The fourth comes from SubsystemC used directly, which is allowed: the facade added a convenient path and closed none.
← → move through sections and cards