定義:(Bridge Pattern)
將抽象和實(shí)現(xiàn)解耦,使得兩者可以獨(dú)立地變化。
類圖:
啟示:
一個(gè)產(chǎn)品的研發(fā),流程主要包括需求分析、產(chǎn)品設(shè)計(jì)、制定計(jì)劃、任務(wù)安排、進(jìn)度把控、產(chǎn)品發(fā)布、后期運(yùn)維。
按照我們一般的設(shè)計(jì)思路,我們可能會(huì)如下設(shè)計(jì):
定義一個(gè)抽象的ProjectManager類,用來定義項(xiàng)目的開發(fā)流程,不同的項(xiàng)目通過繼承來實(shí)現(xiàn)具體的流程。每增加新的項(xiàng)目,就只需要繼承該類重新實(shí)現(xiàn)即可。但這僅適用于某個(gè)單一角色對(duì)產(chǎn)品的管理。
我們知道一個(gè)IT公司的組織架構(gòu)一般由CEO、產(chǎn)品經(jīng)理、項(xiàng)目經(jīng)理和員工組成。CEO負(fù)責(zé)整個(gè)公司運(yùn)行項(xiàng)目的整體把控,產(chǎn)品經(jīng)理負(fù)責(zé)公司的某一條產(chǎn)品線,項(xiàng)目經(jīng)理則負(fù)責(zé)產(chǎn)品線中的某個(gè)項(xiàng)目的開發(fā)管理,而員工就是負(fù)責(zé)項(xiàng)目的開發(fā)工作。
作為一名項(xiàng)目經(jīng)理,職責(zé)可能主要是制定開發(fā)計(jì)劃和任務(wù)分配,并把控進(jìn)度。但若作為一名產(chǎn)品經(jīng)理,職責(zé)可能就需要額外負(fù)責(zé)需求分析、產(chǎn)品設(shè)計(jì)的工作,職位越高,責(zé)任越大嘛。
按照之前的設(shè)計(jì),我們就需要針對(duì)同一個(gè)項(xiàng)目不同的角色分別提供不同的實(shí)現(xiàn),這顯然是不合理的。且每個(gè)角色都被賦予了同樣的流程管理功能,這也是不符合現(xiàn)實(shí)場(chǎng)景的。那如何做到項(xiàng)目管理根據(jù)不同角色和不同項(xiàng)目靈活變化呢?要想做到這一點(diǎn),我們就必須將之前項(xiàng)目管理和項(xiàng)目的緊耦合關(guān)系松松綁。而如何松綁呢,咱們借助『橋接模式』。
Talk is cheap, show you the code!
代碼:
從面向?qū)ο蟮慕嵌龋覀兛梢猿橄蟪鼋?jīng)理和項(xiàng)目?jī)蓚€(gè)對(duì)象,將這些工作流程抽象為具體的行為方法。
那這些行為方法的附屬該如何設(shè)置呢?經(jīng)理作為項(xiàng)目的主要把控者,以上的工作是經(jīng)理的職責(zé)所在。但是,這些工作又都是基于項(xiàng)目的,也就是說我們也可以將這些工作看成是項(xiàng)目本身的行為。你可能會(huì)按以人為本的思想,將這些行為方法定義到經(jīng)理的角色里。但這樣就會(huì)有一個(gè)問題,假設(shè)項(xiàng)目經(jīng)理在項(xiàng)目尚未結(jié)束的時(shí)候因?yàn)槟承┮蛩剞o職了或人事變動(dòng)調(diào)離了,那之前的項(xiàng)目的工作安排就不可控了,這是不允許的。所以最好還是把這些行為方法定義到具體的項(xiàng)目中去。
public abstract class Project
{
public string ProjectName { get; set; }
protected Project(string projectName)
{
ProjectName = projectName;
}
/// <summary>
/// 需求分析
/// </summary>
public abstract void AnalyzeRequirement();
/// <summary>
/// 產(chǎn)品設(shè)計(jì)
/// </summary>
public abstract void DesignProduct();
/// <summary>
/// 制定計(jì)劃
/// </summary>
public abstract void MakePlan();
/// <summary>
/// 任務(wù)分解
/// </summary>
public abstract void ScheduleTask();
/// <summary>
/// 進(jìn)度把控
/// </summary>
public abstract void ControlProcess();
/// <summary>
/// 產(chǎn)品發(fā)布
/// </summary>
public abstract void ReleaseProduct();
/// <summary>
/// 后期運(yùn)維
/// </summary>
public abstract void MaintainProduct();
}
那如何做到不同的角色賦予不同的項(xiàng)目管理職責(zé)呢?我們可以將職責(zé)最少的角色抽象出來。比如我們可以將項(xiàng)目經(jīng)理制定產(chǎn)品計(jì)劃、任務(wù)分配和進(jìn)度把控抽離出來。
public abstract class Manager
{
protected Project CurrentProject { get; }
protected Manager(Project currentProject)
{
CurrentProject = currentProject;
}
/// <summary>
/// 制定計(jì)劃
/// </summary>
public abstract void SchedulePlan();
/// <summary>
/// 任務(wù)分配
/// </summary>
public abstract void AssignTasks();
/// <summary>
/// 進(jìn)度把控
/// </summary>
public abstract void ControlProcess();
/// <summary>
/// 項(xiàng)目管理
/// </summary>
public virtual void ManageProject()
{
SchedulePlan();
AssignTasks();
ControlProcess();
}
}
然后項(xiàng)目經(jīng)理和產(chǎn)品經(jīng)理繼承實(shí)現(xiàn)基本職責(zé),根據(jù)需要?jiǎng)討B(tài)添加額外的職責(zé)。
我們看看項(xiàng)目經(jīng)理的具體實(shí)現(xiàn):
/// <summary>
/// 項(xiàng)目經(jīng)理
/// </summary>
public class ProjectManager : Manager
{
public ProjectManager(Project currentProject) : base(currentProject)
{
}
public override void SchedulePlan()
{
base.CurrentProject.MakePlan();
}
public override void AssignTasks()
{
base.CurrentProject.ScheduleTask();
}
public override void ControlProcess()
{
base.CurrentProject.ControlProcess();
}
public override void ManageProject()
{
Console.WriteLine($"項(xiàng)目經(jīng)理負(fù)責(zé)【{base.CurrentProject.ProjectName}】:");
base.ManageProject();
}
}
再看看產(chǎn)品經(jīng)理的實(shí)現(xiàn):
/// <summary>
/// 產(chǎn)品經(jīng)理
/// </summary>
public class ProductManger : Manager
{
public ProductManger(Project currentProject) : base(currentProject)
{
}
public override void SchedulePlan()
{
base.CurrentProject.MakePlan();
}
public override void AssignTasks()
{
base.CurrentProject.ScheduleTask();
}
public override void ControlProcess()
{
base.CurrentProject.ControlProcess();
}
public void AnalyseRequirement()
{
base.CurrentProject.AnalyzeRequirement();
}
public void DesignProduct()
{
base.CurrentProject.DesignProduct();
}
public override void ManageProject()
{
AnalyseRequirement();
DesignProduct();
base.ManageProject();
}
public override void ManageProject()
{
Console.WriteLine($"產(chǎn)品經(jīng)理負(fù)責(zé)【{base.CurrentProject.ProjectName}】:");
AnalyseRequirement();
DesignProduct();
base.ManageProject();
}
}
可以看到我們?yōu)楫a(chǎn)品經(jīng)理額外添加了需求分析和產(chǎn)品設(shè)計(jì)的職責(zé)。
下面我們看看最終的場(chǎng)景類:
Project webProject = new WebProject("Web項(xiàng)目");
Manager projectManager = new ProjectManager(webProject);
Manager productManager = new ProductManger(webProject);
projectManager.ManageProject();
productManager.ManageProject();
Console.ReadLine();
總結(jié):
通過上面的demo,我們解決了之前通過繼承設(shè)計(jì)的弊端,即項(xiàng)目管理和項(xiàng)目不能靈活適應(yīng)變化。通過引入橋接模式,將項(xiàng)目管理和項(xiàng)目解耦,我們實(shí)現(xiàn)了項(xiàng)目管理(抽象)和項(xiàng)目(實(shí)現(xiàn))的分離。橋接模式的意圖還是對(duì)變化的封裝,盡量把可能變化的因素封裝到最細(xì)、最小的邏輯單元中,避免風(fēng)險(xiǎn)擴(kuò)散。而這也正是橋接模式的精髓所在。
優(yōu)缺點(diǎn):
橋接模式將抽象和實(shí)現(xiàn)分離,實(shí)現(xiàn)可以不受抽象的約束,不用再綁定在一個(gè)固定的抽象層次上;抽象和實(shí)現(xiàn)均可自由擴(kuò)展。
應(yīng)用場(chǎng)景:
- 不希望或不適用使用繼承的場(chǎng)景
- 接口或抽象類不穩(wěn)定的場(chǎng)景
- 重用性要求較高的場(chǎng)景
- 解決多層繼承
實(shí)際案例:
數(shù)據(jù)庫(kù):Orace、SQL Server
數(shù)據(jù)庫(kù)訪問技術(shù):NHibernate、EntityFramework
每種數(shù)據(jù)庫(kù)都可以用不同的數(shù)據(jù)庫(kù)訪問技術(shù)。