A Facade pattern hides the complexities of the system and provides an interface to the client from where the client can access the system. Dividing a system into subsystems helps reduce complexity. We need to minimize the communication and dependencies between subsystems. For this, we introduce a facade object that provides a single, simplified interface to the more general facilities of a subsystem.
Examples
The SCP command is a shortcut for SSH commands. A remote file copy could be done writing several commands with an SSH connection but it can be done in one command with SCP. So the SCP command is a facade for the SSH commands. Although it may not be coded in the object programming paradigm, it is a good illustration of the design pattern.
Cost
This pattern is very easy and has not additional cost.
Creation
This pattern is very easy to create.
Maintenance
This pattern is very easy to maintain.
Removal
This pattern is very easy to remove too.
Advises
- Do not use this pattern to mask only three or four method calls.
Implementations
This is an abstract example of how a client ("you") interacts with a facade (the "computer") to a complex system (internal computer parts, like CPU and HardDrive).
/* Complex parts */ class CPU{ publicvoidfreeze(){...} publicvoidjump(longposition){...} publicvoidexecute(){...} }
class Memory{ publicvoidload(longposition,byte[]data){...} }
class HardDrive{ publicbyte[]read(longlba,intsize){...} }
/* Facade */ class Computer{ privateCPUprocessor; privateMemoryram; privateHardDrivehd; publicComputer(){ this.processor=newCPU(); this.ram=newMemory(); this.hd=newHardDrive(); } publicvoidstart(){ processor.freeze(); ram.load(BOOT_ADDRESS,hd.read(BOOT_SECTOR,SECTOR_SIZE)); processor.jump(BOOT_ADDRESS); processor.execute(); } }
/* Client */ class You{ publicstaticvoidmain(String[]args){ Computerfacade=newComputer(); facade.start(); } }
usingSystem; namespaceFacade { publicclassCPU { publicvoidFreeze(){} publicvoidJump(longaddr){} publicvoidExecute(){} } publicclassMemory { publicvoidLoad(longposition,byte[]data){} } publicclassHardDrive { publicbyte[]Read(longlba,intsize){returnnull;} } publicclassComputer { varcpu=newCPU(); varmemory=newMemory(); varhardDrive=newHardDrive(); publicvoidStartComputer() { cpu.Freeze(); memory.Load(0x22,hardDrive.Read(0x66,0x99)); cpu.Jump(0x44); cpu.Execute(); } } publicclassSomeClass { publicstaticvoidMain(string[]args) { varfacade=newComputer(); facade.StartComputer(); } } }
# Complex parts classCPU deffreeze;puts'CPU: freeze';end defjump(position);puts"CPU: jump to #{position}";end defexecute;puts'CPU: execute';end end classMemory defload(position,data) puts"Memory: load #{data} at #{position}" end end classHardDrive defread(lba,size) puts"HardDrive: read sector #{lba} (#{size} bytes)" return'hdd data' end end # Facade classComputer BOOT_ADDRESS=0 BOOT_SECTOR=0 SECTOR_SIZE=512 definitialize @cpu=CPU.new @memory=Memory.new @hard_drive=HardDrive.new end defstart_computer @cpu.freeze @memory.load(BOOT_ADDRESS,@hard_drive.read(BOOT_SECTOR,SECTOR_SIZE)) @cpu.jump(BOOT_ADDRESS) @cpu.execute end end # Client facade=Computer.new facade.start_computer
# Complex parts classCPU: deffreeze(self): pass defjump(self, position): pass defexecute(self): pass classMemory: defload(self, position, data): pass classHardDrive: defread(self, lba, size): pass # Facade classComputer: def__init__(self): self.cpu = CPU() self.memory = Memory() self.hard_drive = HardDrive() defstart_computer(self): self.cpu.freeze() self.memory.load(0, self.hard_drive.read(0, 1024)) self.cpu.jump(10) self.cpu.execute() # Client if __name__ == '__main__': facade = Computer() facade.start_computer()
/* Complex parts */ class CPU { public function freeze() { /* ... */ } public function jump( $position ) { /* ... */ } public function execute() { /* ... */ } } class Memory { public function load( $position, $data ) { /* ... */ } } class HardDrive { public function read( $lba, $size ) { /* ... */ } } /* Facade */ class Computer { protected $cpu = null; protected $memory = null; protected $hardDrive = null; public function __construct() { $this->cpu = new CPU(); $this->memory = new Memory(); $this->hardDrive = new HardDrive(); } public function startComputer() { $this->cpu->freeze(); $this->memory->load( BOOT_ADDRESS, $this->hardDrive->read( BOOT_SECTOR, SECTOR_SIZE ) ); $this->cpu->jump( BOOT_ADDRESS ); $this->cpu->execute(); } } /* Client */ $facade = new Computer(); $facade->startComputer();
/* Complex parts */ varCPU=function(){}; CPU.prototype={ freeze:function(){ console.log('CPU: freeze'); }, jump:function(position){ console.log('CPU: jump to '+position); }, execute:function(){ console.log('CPU: execute'); } }; varMemory=function(){}; Memory.prototype={ load:function(position,data){ console.log('Memory: load "'+data+'" at '+position); } }; varHardDrive=function(){}; HardDrive.prototype={ read:function(lba,size){ console.log('HardDrive: read sector '+lba+'('+size+' bytes)'); return'hdd data'; } }; /* Facade */ varComputer=function(){ varcpu,memory,hardDrive; cpu=newCPU(); memory=newMemory(); hardDrive=newHardDrive(); varconstant=function(name){ varconstants={ BOOT_ADDRESS:0, BOOT_SECTOR:0, SECTOR_SIZE:512 }; returnconstants[name]; }; this.startComputer=function(){ cpu.freeze(); memory.load(constant('BOOT_ADDRESS'),hardDrive.read(constant('BOOT_SECTOR'),constant('SECTOR_SIZE'))); cpu.jump(constant('BOOT_ADDRESS')); cpu.execute(); } }; /* Client */ varfacade=newComputer(); facade.startComputer();
/* Complex Parts */ /* CPU.as */ package { publicclassCPU { publicfunctionfreeze():void { trace("CPU::freeze"); } publicfunctionjump(addr:Number):void { trace("CPU::jump to",String(addr)); } publicfunctionexecute():void { trace("CPU::execute"); } } } /* Memory.as */ package { importflash.utils.ByteArray; publicclassMemory { publicfunctionload(position:Number,data:ByteArray):void { trace("Memory::load position:",position,"data:",data); } } } /* HardDrive.as */ package { importflash.utils.ByteArray; publicclassHardDrive { publicfunctionread(lba:Number,size:int):ByteArray { trace("HardDrive::read returning null"); returnnull; } } } /* The Facade */ /* Computer.as */ package { publicclassComputer { publicstaticconstBOOT_ADDRESS:Number=0x22; publicstaticconstBOOT_SECTOR:Number=0x66; publicstaticconstSECTOR_SIZE:int=0x200; privatevar_cpu:CPU; privatevar_memory:Memory; privatevar_hardDrive:HardDrive; publicfunctionComputer() { _cpu=newCPU(); _memory=newMemory(); _hardDrive=newHardDrive(); } publicfunctionstartComputer():void { _cpu.freeze(); _memory.load(BOOT_ADDRESS,_hardDrive.read(BOOT_SECTOR,SECTOR_SIZE)); _cpu.jump(BOOT_ADDRESS); _cpu.execute(); } } } /* Client.as : This is the application's Document class */ package { importflash.display.MovieClip; publicclassClientextendsMovieClip { privatevar_computer:Computer; publicfunctionClient() { _computer=newComputer(); _computer.startComputer(); } } }
/* Complex parts */ packageintel{ classCPU{ deffreeze()=??? defjump(position:Long)=??? defexecute()=??? } } packageram.plain{ classMemory{ defload(position:Long,data:Array[Byte])=??? } } packagehdd{ classHardDrive{ defread(lba:Long,size:Int):Array[Byte]=??? } }
/* Facade */ //imports for the facade importcommon.patterns.intel.CPU importcommon.patterns.ram.plain.Memory importcommon.patterns.hdd.HardDrive packagepk{ classComputerFacade(conf:String){ valprocessor:CPU=newCPU valram:Memory=newMemory valhd:HardDrive=newHardDrive valBOOT_ADDRESS:Long=??? valBOOT_SECTOR:Long=??? valSECTOR_SIZE:Int=??? defstart()={ processor.freeze() ram.load(BOOT_ADDRESS,hd.read(BOOT_SECTOR,SECTOR_SIZE)) processor.jump(BOOT_ADDRESS) processor.execute() } } }
//imports for your package importcommon.patterns.pk.ComputerFacade /* Client */ objectYou{ defmain(args:Array[String]){ newComputerFacade("conf").start() } }
programFacade; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type (* complex parts - > Subsystem *) TCPU=class procedureFreeze; procedureJump(position:Integer); procedureExecute; end; TMemory=class procedureLoad(position:Integer;data:string); end; THardDrive=class functionRead(lba,size:Integer):string; end; (* Facade *) TComputer=class fCPU:TCPU; fMemory:TMemory; fHardDrive:THardDrive; const BOOT_ADDRESS:Integer=0; BOOT_SECTOR:Integer=0; SECTOR_SIZE:Integer=512; public procedureStart_Computer; constructorCreate; end; { TCPU } procedureTCPU.Execute; begin WriteLn('CPU: execute'); end; procedureTCPU.Freeze; begin WriteLn('CPU: freese'); end; procedureTCPU.Jump(position:Integer); begin WriteLn('CPU: jump to '+IntToStr(position)); end; { TMemory } procedureTMemory.Load(position:Integer;data:string); begin WriteLn('Memory: load "'+data+'" at '+IntToStr(position)); end; { THardDrive } functionTHardDrive.Read(lba,size:Integer):string; begin WriteLn('HardDrive: read sector '+IntToStr(lba)+' ('+IntToStr(size)+ ' bytes)'); Result:='hdd data'; end; { TComputer } constructorTComputer.Create; begin fCPU:=TCPU.Create; fMemory:=TMemory.Create; fHardDrive:=THardDrive.Create; end; procedureTComputer.Start_Computer; begin fCPU.Freeze; fMemory.Load(BOOT_ADDRESS,fHardDrive.Read(BOOT_SECTOR,SECTOR_SIZE)); fCPU.Jump(BOOT_ADDRESS); fCPU.Execute; end; var facad:TComputer; begin try { TODO -oUser -cConsole Main : Insert code here } facad:=TComputer.Create; facad.Start_Computer; WriteLn(#13#10+'Press any key to continue...'); ReadLn; facad.Free; except onE:Exceptiondo WriteLn(E.ClassName,': ',E.Message); end; end.
