問題描述:當一個函數中處理一個特性時,如果特性包含了多個職責,則這個函數也包含了多個職責。只有通讀整個函數的邏輯結構後才能知道這個函數具體實現什麼功能。
單一職責原則要求一個類應該只有一個變更理由,函數也是如此。
重構清晰度:將包含多職責的函數拆分成多個更小的函數,每個函數只處理其中一條職責。這樣重構之後增加了代碼的清晰度,但是代碼的適應性沒有得到任何提高。需要修改其中一個函數的方法時,需要修改方法內容,違背了開閉原則。
重構抽象:根據上面拆分出來的多個函數,設計實現單一職責的接口以及實現類。在調用處引用創建的接口來執行對應的工作。接口實現類則僅有單一職責變更時纔會進行改變。
單一職責原則和修飾器模式
修飾器模式(Decorator Pattern, DP)能夠很好的確保每個類只有單一職責。一般情況下,完成很多事情的類不能輕易的將職責劃分到其他類型中,因爲很多職責看起來是相互關聯的。
修飾器模式的前置條件:每個修飾器類實現一個接口且能同時接受一個或多個同一個接口實例作爲構造函數的輸入參數。這樣的好處在於可以給已經實現了某個特定接口的類添加功能,而且修飾器同時也是所需接口的一個實現,並且對用戶不可見。
public interface Icomponent
{
void Something();
}
///////
public class ConcreteComponent:Icomponent
{
public void Something(){ ////// };
}
////////////
public class DecoratorComponent:Icomponent
{
public DecoratorComponent(Icomponent decoratedComponent)
{
this.decoratedComponent = decoratedComponent;
}
public void Something()
{
// Do Other Things
decoratedComponent.Something();
};
}
}
1、 複合模式(Composite Pattern):讓某個接口的一組實例看作該接口的一個實例。客戶端只需要接受接口的一個實例,在無需任何改變的情況下就能隱式的使用該接口的一組實例。
public interface IComponent
{
void Something();
}
public class Leaf : IComponent
{
public void Something()
{
}
}
public class CompositeComponent : IComponent
{
List<IComponent> children = null;
public CompositeComponent()
{
children = new List<IComponent>();
}
public void Something()
{
foreach (IComponent child in children)
{
child.Something();
}
}
public void AddComponent(IComponent component)
{
children.Add(component);
}
public void RemoveComponent(IComponent component)
{
children.Remove(component);
}
}
{
static void Main(string[] args)
{
var composite = new CompositeComponent();
composite.AddComponent(new Leaf());
composite.AddComponent(new Leaf());
composite.AddComponent(new Leaf());
component = composite;
component.Something();
}
static IComponent component;
}
多用於顯示樹結構。
2、謂詞修飾器(Predicate Decorator):能夠很好的消除客戶端代碼中的條件執行語句。將條件判斷語句提出一個接口,將接口放到謂詞修飾器中進行判斷。
3、分支修飾器:在謂詞修飾器基礎上進行修改,傳入三個參數,當謂詞爲true 或false時分別執行兩個不同的接口實例操作。
4、延遲修飾器:延遲修飾器允許客戶端提供摸個接口的引用,但是直到第一次使用他時才進行實例化。同牀客戶端直到看到傳入參數類型爲Lazy<T>類型時纔會察覺到延遲實例的存在。但是不應該讓他們知道延遲實例存在的細節信息。
// 客戶端可以看到具體的延遲接口,適應性差,不能接收非延遲性IComponent接口
public class ComponentClient
{
private Lazy<IComponent> component;
public ComponentClient(Lazy<IComponent> component)
{
this.component = component;
}
public void Runing()
{
component.Value.Something();
}
}
// 使用延遲適配器,客戶端可以兼容延遲與非延遲接口
public class LazyComponent : IComponent
{
private Lazy<IComponent> component;
public LazyComponent(Lazy<IComponent> component)
{
this.component = component;
}
public void Runing()
{
component.Value.Something();
}
}
public class ComponentClient
{
private IComponent component;
public ComponentClient(IComponent component)
{
this.component = component;
}
public void Runing()
{
component.Something();
}
}
5、日誌記錄修飾器:
6、性能修飾器:
7、異步修飾器:
8、修飾屬性和事件
用策略模式替代Switch語句:
任何使用Switch語句的場合,都可以通過策略模式將複雜性委託給依賴的接口以簡化客戶端代碼。策略模式能夠提供更好的適應變更的能力。