Bridgeパターンは、クラスの骨格(インターフェイス。ActionScript文法のinterfaceというわけではない)と中身(ソース)を分離する手法である。 骨組みと中身に依存関係がなくなるため、両者を別個に作成できる環境が与えられる。 骨組みと中身に依存関係がないということは、特定の骨組みに対して中身の入れ替えが可能であることを意味する。 Bridgeパターンの場合、中身の入れ替えは簡単なので 状況に応じて中身の入れ替えが必要なアプリケーションの制作などに都合がよいであろう (例えばWindowsとMacで動作を変更するなど)。
構造がAdapterパターンと似ているが、 Adapterパターンは既存のクラスに対して行う手法であるのに対し(改築)、 Bridgeパターンはプロジェクト全体の設計を見通して投入される(新築)という点で両者は大きく異なる。
花屋を営業する経営者がいたとして、この経営者と花屋の関係をクラスに例えて考えてみよう。 花屋にはおそらく営業日と定休日があり、 営業日と定休日では花屋の外観も販売員の行動も異なるだろう。 つまり営業日と定休日で花屋は実質別モノであると考えると、 営業日の花屋と定休日の花屋という二つのクラスを作成し、曜日によって出現する花屋を制御してやるという経営スタイルが考えられる。 しかしこの場合、販売員(の行動)を含んだ花屋クラスとして作成してしまうと1クラスが巨大になってしまう。 また、別のお店を開店した場合、同じように営業日クラスと定休日クラスをイチから作らなければならなくなる。 この手法はお店が増えれば増えるほどやっかいになりそうである。
そこで店クラスと販売員クラスを分離する手法を考えてみよう。 店は店、販売員は販売員として作成してしまい、曜日によって店で働く販売員を入れ替える形式をとることにするのである。 以下の例では、販売店(AShop.as)と販売員(IVendor.as)の関係にBridgeパターンを用いている。 AShopクラスがIvendorクラスへの参照をプロパティ(_vendor)として保持しているところに注意してもらいたい。 これによりAShopクラスを継承するクラスはいつでも販売員の入れ替えが可能になるのである。 例では、花屋(FlowerShop.as、定休日水曜日)と薬屋(Pharmacy.as、定休日日曜日)を作成してある。 実際の販売員は営業日販売員(WorkingVendor.as)と休業日販売員(NonWorkingVendor.as)を作成し、 FlowerShopクラスとPharmacyクラスそれぞれで曜日による入れ替え作業を行っている。 なお、曜日によって販売員を設定するクラス(VendorCreator.as)を別個に作成してあるが、 これの存在はBridgeパターンと何ら関係ない。
//main.as package { import flash.display.Sprite; public class main extends Sprite{ public function main(){ //Sunday var year:Object = 2009; var month:Number = 5; var day:Number = 3; var sunday:Date = new Date(year, month - 1, day); trace("<Sunday - flowershop>"); var flowerShop:FlowerShop = new FlowerShop(sunday); trace("\n<Sunday - pharmacy>"); var pharmacy:Pharmacy = new Pharmacy(sunday); } } }
//main.as - output
Sunday @ flowershop
The vendor opens the shop.
[The flower shop is now open.]
The vendor says hello.
The vendor sells items.
The vendor closes the shop.
[The flower shop is now close.]
Sunday @ pharmacy
The vendor doesn't have to open the shop, as today is not a working day!
//AShop.as (Abstract) package{ public class AShop{ protected var _vendor:IVendor; public function AShop(){ } public function open():void{ //must be overridden in a subclass. } public function close():void{ //must be overridden in a subclass. } } }
//FlowerShop.as package{ public class FlowerShop extends AShop{ public function FlowerShop(date:Date){ _vendor = VendorCreator.flowerShopVendor(this, date); _vendor.openShop(); } override public function open():void{ trace("[The flower shop is now open.]"); _vendor.sayHello(); _vendor.sellItems(); _vendor.closeShop(); } override public function close():void{ trace("[The flower shop is now close.]"); } } }
//Pharmacy.as package{ public class Pharmacy extends AShop{ public function Pharmacy(date:Date){ _vendor = VendorCreator.pharmacyVendor(this, date); _vendor.openShop(); } override public function open():void{ trace("[The parmacy is now open.]"); _vendor.sayHello(); _vendor.sellItems(); _vendor.closeShop(); } override public function close():void{ trace("[The parmacy is now close.]"); } } }
//Ivendor.as (Interface) package{ public interface IVendor{ function openShop():void; function sayHello():void; function sellItems():void; function closeShop():void; } }
//WorkingVendor.as (Implementation) package{ public class WorkingVendor implements IVendor{ protected var _shop:AShop; public function WorkingVendor(shop:AShop){ _shop = shop; } public function openShop():void{ trace("The vendor opens the shop."); _shop.open(); } public function sayHello():void{ trace("The vendor says hello."); } public function sellItems():void{ trace("The vendor sells items."); } public function closeShop():void{ trace("The vendor closes the shop."); _shop.close(); } } }
//NonWorkingVendor.as (Implementation) package{ public class NonWorkingVendor implements IVendor{ public function NonWorkingVendor(){ } public function openShop():void{ trace("The vendor doesn't have to open the shop, as today is not a working day!"); } public function sayHello():void{ //Nothing should be done. } public function sellItems():void{ //Nothing should be done. } public function closeShop():void{ //Nothing should be done. } } }
//VendorCreator.as (static) package{ public class VendorCreator{ private static const SUNDAY:Number = 0; private static const WEDNESDAY:Number = 3; public function VendorCreator(){ } static public function flowerShopVendor(shop:AShop, date:Date):IVendor{ if (date.getDay() == VendorCreator.WEDNESDAY){ return new NonWorkingVendor(); } return new WorkingVendor(shop); } static public function pharmacyVendor(shop:AShop, date:Date):IVendor{ if (date.getDay() == VendorCreator.SUNDAY){ return new NonWorkingVendor(); } return new WorkingVendor(shop); } } }