外观
外观
外观模式隐藏了系统的复杂性,并为客户端提供了一个接口,客户端可以通过该接口访问系统。将系统划分为子系统有助于降低复杂性。我们需要最小化子系统之间的通信和依赖关系。为此,我们引入了外观对象,它为子系统更通用的功能提供一个单一的、简化的接口。
示例
SCP
命令是SSH命令的快捷方式。可以使用SSH连接编写多个命令来完成远程文件复制,但可以使用SCP
命令在一个命令中完成。因此,SCP
命令是SSH命令的外观。虽然它可能没有用面向对象编程的方式编码,但它很好地说明了设计模式。
成本
这种模式非常容易,没有额外的成本。
创建
这种模式非常容易创建。
维护
这种模式非常容易维护。
移除
这种模式也很容易移除。
建议
- 不要使用这种模式来掩盖只有三到四个方法调用。
实现
Java实现
这是一个关于客户端(“你”)如何与外观(“电脑”)交互以访问复杂系统(内部电脑部件,如CPU和硬盘)的抽象示例。
/* Complex parts */
class CPU {
public void freeze() { ... }
public void jump(long position) { ... }
public void execute() { ... }
}
class Memory {
public void load(long position, byte[] data) { ... }
}
class HardDrive {
public byte[] read(long lba, int size) { ... }
}
/* Facade */
class Computer {
private CPU processor;
private Memory ram;
private HardDrive hd;
public Computer() {
this.processor = new CPU();
this.ram = new Memory();
this.hd = new HardDrive();
}
public void start() {
processor.freeze();
ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
processor.jump(BOOT_ADDRESS);
processor.execute();
}
}
/* Client */
class You {
public static void main(String[] args) {
Computer facade = new Computer();
facade.start();
}
}
C#实现
using System;
namespace Facade
{
public class CPU
{
public void Freeze() { }
public void Jump(long addr) { }
public void Execute() { }
}
public class Memory
{
public void Load(long position, byte[] data) { }
}
public class HardDrive
{
public byte[] Read(long lba, int size) { return null; }
}
public class Computer
{
var cpu = new CPU();
var memory = new Memory();
var hardDrive = new HardDrive();
public void StartComputer()
{
cpu.Freeze();
memory.Load(0x22, hardDrive.Read(0x66, 0x99));
cpu.Jump(0x44);
cpu.Execute();
}
}
public class SomeClass
{
public static void Main(string[] args)
{
var facade = new Computer();
facade.StartComputer();
}
}
}
Ruby实现
# Complex parts
class CPU
def freeze; puts 'CPU: freeze'; end
def jump(position); puts "CPU: jump to #{position}"; end
def execute; puts 'CPU: execute'; end
end
class Memory
def load(position, data)
puts "Memory: load #{data} at #{position}"
end
end
class HardDrive
def read(lba, size)
puts "HardDrive: read sector #{lba} (#{size} bytes)"
return 'hdd data'
end
end
# Facade
class Computer
BOOT_ADDRESS = 0
BOOT_SECTOR = 0
SECTOR_SIZE = 512
def initialize
@cpu = CPU.new
@memory = Memory.new
@hard_drive = HardDrive.new
end
def start_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
Python实现
# Complex parts
class CPU:
def freeze(self): pass
def jump(self, position): pass
def execute(self): pass
class Memory:
def load(self, position, data): pass
class HardDrive:
def read(self, lba, size): pass
# Facade
class Computer:
def __init__(self):
self.cpu = CPU()
self.memory = Memory()
self.hard_drive = HardDrive()
def start_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()
PHP实现
/* 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();
JavaScript实现
/* Complex parts */
var CPU = function () {};
CPU.prototype = {
freeze: function () {
console.log('CPU: freeze');
},
jump: function (position) {
console.log('CPU: jump to ' + position);
},
execute: function () {
console.log('CPU: execute');
}
};
var Memory = function () {};
Memory.prototype = {
load: function (position, data) {
console.log('Memory: load "' + data + '" at ' + position);
}
};
var HardDrive = function () {};
HardDrive.prototype = {
read: function (lba, size) {
console.log('HardDrive: read sector ' + lba + '(' + size + ' bytes)');
return 'hdd data';
}
};
/* Facade */
var Computer = function () {
var cpu, memory, hardDrive;
cpu = new CPU();
memory = new Memory();
hardDrive = new HardDrive();
var constant = function (name) {
var constants = {
BOOT_ADDRESS: 0,
BOOT_SECTOR: 0,
SECTOR_SIZE: 512
};
return constants[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 */
var facade = new Computer();
facade.startComputer();
ActionScript 3.0实现
/* Complex Parts */
/* CPU.as */
package
{
public class CPU
{
public function freeze():void
{
trace("CPU::freeze");
}
public function jump(addr:Number):void
{
trace("CPU::jump to", String(addr));
}
public function execute():void
{
trace("CPU::execute");
}
}
}
/* Memory.as */
package
{
import flash.utils.ByteArray;
public class Memory
{
public function load(position:Number, data:ByteArray):void
{
trace("Memory::load position:", position, "data:", data);
}
}
}
/* HardDrive.as */
package
{
import flash.utils.ByteArray;
public class HardDrive
{
public function read(lba:Number, size:int):ByteArray
{
trace("HardDrive::read returning null");
return null;
}
}
}
/* The Facade */
/* Computer.as */
package
{
public class Computer
{
public static const BOOT_ADDRESS:Number = 0x22;
public static const BOOT_SECTOR:Number = 0x66;
public static const SECTOR_SIZE:int = 0x200;
private var _cpu:CPU;
private var _memory:Memory;
private var _hardDrive:HardDrive;
public function Computer()
{
_cpu = new CPU();
_memory = new Memory();
_hardDrive = new HardDrive();
}
public function startComputer():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
{
import flash.display.MovieClip;
public class Client extends MovieClip
{
private var _computer:Computer;
public function Client()
{
_computer = new Computer();
_computer.startComputer();
}
}
}
Scala实现
/* Complex parts */
package intel {
class CPU {
def freeze() = ???
def jump(position: Long) = ???
def execute() = ???
}
}
package ram.plain {
class Memory {
def load(position: Long, data: Array[Byte]) = ???
}
}
package hdd {
class HardDrive {
def read(lba: Long, size: Int): Array[Byte] = ???
}
}
/* Facade */
//imports for the facade
import common.patterns.intel.CPU
import common.patterns.ram.plain.Memory
import common.patterns.hdd.HardDrive
package pk {
class ComputerFacade(conf: String) {
val processor: CPU = new CPU
val ram: Memory = new Memory
val hd: HardDrive = new HardDrive
val BOOT_ADDRESS: Long = ???
val BOOT_SECTOR: Long = ???
val SECTOR_SIZE: Int = ???
def start() = {
processor.freeze()
ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE))
processor.jump(BOOT_ADDRESS)
processor.execute()
}
}
}
//imports for your package
import common.patterns.pk.ComputerFacade
/* Client */
object You {
def main(args: Array[String]) {
new ComputerFacade("conf").start()
}
}
Delphi实现
program Facade;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
(* complex parts - > Subsystem *)
TCPU = class
procedure Freeze;
procedure Jump(position: Integer);
procedure Execute;
end;
TMemory = class
procedure Load(position: Integer; data: string);
end;
THardDrive = class
function Read(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
procedure Start_Computer;
constructor Create;
end;
{ TCPU }
procedure TCPU.Execute;
begin
WriteLn('CPU: execute');
end;
procedure TCPU.Freeze;
begin
WriteLn('CPU: freese');
end;
procedure TCPU.Jump(position: Integer);
begin
WriteLn('CPU: jump to ' + IntToStr(position));
end;
{ TMemory }
procedure TMemory.Load(position: Integer; data: string);
begin
WriteLn('Memory: load "' + data + '" at ' + IntToStr(position));
end;
{ THardDrive }
function THardDrive.Read(lba, size: Integer): string;
begin
WriteLn('HardDrive: read sector ' + IntToStr(lba) + ' (' + IntToStr(size) +
' bytes)');
Result := 'hdd data';
end;
{ TComputer }
constructor TComputer.Create;
begin
fCPU := TCPU.Create;
fMemory := TMemory.Create;
fHardDrive := THardDrive.Create;
end;
procedure TComputer.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
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.