【Codeforces 809E】Surprise me!(莫比烏斯反演 & 虛樹)
1. 設計模式的簡介
設計模式(Design pattern)代表了最佳的實踐,通常被有經驗的面向物件的軟體開發人員所採用。設計模式是軟體開發人員在軟體開發過程中面臨的一般問題的解決方案。這些解決方案是眾多軟體開發人員經過相當長的一段時間的試驗和錯誤總結出來的。
設計模式是一套被反覆使用的、多數人知曉的、經過分類編目的、程式碼設計經驗的總結。使用設計模式是為了重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使程式碼編制真正工程化,設計模式是軟體工程的基石,如同大廈的一塊塊磚石一樣。專案中合理地運用設計模式可以完美地解決很多問題,每種模式在現實中都有相應的原理來與之對應,每種模式都描述了一個在我們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是設計模式能被廣泛應用的原因。
2. 計模式的使用
設計模式在軟體開發中的兩個主要用途。
開發人員的共同平臺
設計模式提供了一個標準的術語系統,且具體到特定的情景。例如,單例設計模式意味著使用單個物件,這樣所有熟悉單例設計模式的開發人員都能使用單個物件,並且可以通過這種方式告訴對方,程式使用的是單例模式。
最佳的實踐
設計模式已經經歷了很長一段時間的發展,它們提供了軟體開發過程中面臨的一般問題的最佳解決方案。學習這些模式有助於經驗不足的開發人員通過一種簡單快捷的方式來學習軟體設計。
3. 設計模式的分類
根據設計模式的參考書 Design Patterns - Elements of Reusable Object-Oriented Software(中文譯名:設計模式 - 可複用的面向物件軟體元素)
這些模式可以分為三大類:
-
建立型模式(Creational Patterns)、
-
結構型模式(Structural Patterns)、
-
為型模式(Behavioral Patterns)。
-
當然,我們還會討論另一類設計模式:J2EE 設計模式。
3.1 建立型模式
這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new 運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。
- 工廠模式(Factory Pattern)
- 抽象工廠模式(Abstract Factory Pattern)
- 單例模式(Singleton Pattern)
- 建造者模式(Builder Pattern)
- 原型模式(Prototype Pattern)
1. 單例模式
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
這種模式涉及到一個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一的物件的方式,可以直接訪問,不需要例項化該類的物件。
注意:
- 1、單例類只能有一個例項。
- 2、單例類必須自己建立自己的唯一例項。
- 3、單例類必須給所有其他物件提供這一例項。
//懶漢式,執行緒不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//懶漢式,執行緒安全,用synchronized修飾
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//餓漢式,內部靜態類
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
2. 工廠模式
意圖:定義一個建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。
主要解決:主要解決介面選擇的問題。
何時使用:我們明確地計劃不同條件下建立不同例項時。
如何解決:讓其子類實現工廠介面,返回的也是一個抽象的產品。
關鍵程式碼:建立過程在其子類執行。
應用例項: 1、您需要一輛汽車,可以直接從工廠裡面提貨,而不用去管這輛汽車是怎麼做出來的,以及這個汽車裡面的具體實現。 2、Hibernate 換資料庫只需換方言和驅動就可以。
優點: 1、一個呼叫者想建立一個物件,只要知道其名稱就可以了。 2、擴充套件性高,如果想增加一個產品,只要擴充套件一個工廠類就可以。 3、遮蔽產品的具體實現,呼叫者只關心產品的介面。
缺點:每次增加一個產品時,都需要增加一個具體類和物件實現工廠,使得系統中類的個數成倍增加,在一定程度上增加了系統的複雜度,同時也增加了系統具體類的依賴。這並不是什麼好事。
使用場景: 1、日誌記錄器:記錄可能記錄到本地硬碟、系統事件、遠端伺服器等,使用者可以選擇記錄日誌到什麼地方。 2、資料庫訪問,當用戶不知道最後系統採用哪一類資料庫,以及資料庫可能有變化時。 3、設計一個連線伺服器的框架,需要三個協議,"POP3"、"IMAP"、"HTTP",可以把這三個作為產品類,共同實現一個介面。
注意事項:作為一種建立類模式,在任何需要生成複雜物件的地方,都可以使用工廠方法模式。有一點需要注意的地方就是複雜物件適合使用工廠模式,而簡單物件,特別是只需要通過 new 就可以完成建立的物件,無需使用工廠模式。如果使用工廠模式,就需要引入一個工廠類,會增加系統的複雜度。
實現
- 建立一個產品介面
Shape.java
//產品介面
public interface Shape{
void draw();
}
- 建立實現產品介面的實體類
Rectangle.java
public class Circle imlements Shape{
@Override
public void draw(){
System.out.println("Inside Rectangle::draw() method.")
}
}
Square.java
public class Square imlements Shape{
@Override
public void draw(){
System.out.println("Inside Square::draw() method.")
}
}
- 建立一個工廠,生成基於給定資訊的實體類的物件
ShapeFactory
public class Factory{
//使用getShape方法獲取形狀型別的物件
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equals("circle")){
return new Circle();
}else if(shapeType.equals("square")){
return new Square();
}
}
}
- 使用工廠,通過傳遞類資訊來獲取實體類的物件
public class FactoryPatternDemo {
public static void main(String[] args) {
Factory factory = new Factory();
//獲取 Circle 的物件,並呼叫它的 draw 方法
Shape shape1 = Factory.getShape("circle");
//呼叫 Circle 的 draw 方法
shape1.draw();
//獲取 Rectangle 的物件,並呼叫它的 draw 方法
Shape shape2 = Factory.getShape("square");
shape2.draw();
}
}
2. 抽象的工廠模式
- 產品的介面和實現介面的具體類
//抽象工廠,具有生產集體工廠的功能
public interface Producer{
public Shape provider;
}
- 具體的工廠
//專門生成Circle的工廠
class CircleFactory{
@Override
public Shape provider(){
return new Circle();
}
}
//專門生成Square的工廠
class SquareFactory{
@Override
public Shape privider(){
return new Square();
}
}
3.2 結構性模式
這些設計模式關注類和物件的組合。繼承的概念被用來組合介面和定義組合物件獲得型功能的方式。
- 介面卡模式(Adapter Pattern)
- 橋接模式(Bridge Pattern)
- 過濾器模式(Filter、Criteria Pattern)
- 組合模式(Composite Pattern)
- 裝飾器模式(Decorator Pattern)
- 外觀模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
- 代理模式(Proxy Pattern)
3.3 行為型模式
這些設計模式特別關注物件之間的通訊。
- 責任鏈模式(Chain of Responsibility Pattern)
- 命令模式(Command Pattern)
- 直譯器模式(Interpreter Pattern)
- 迭代器模式(Iterator Pattern)
- 中介者模式(Mediator Pattern)
- 備忘錄模式(Memento Pattern)
- 觀察者模式(Observer Pattern)
- 狀態模式(State Pattern)
- 空物件模式(Null Object Pattern)
- 策略模式(Strategy Pattern)
- 模板模式(Template Pattern)
- 訪問者模式(Visitor Pattern)
3.4 J2EE 模式
這些設計模式特別關注表示層。這些模式是由 Sun Java Center 鑑定的。
- MVC 模式(MVC Pattern)
- 業務代表模式(Business Delegate Pattern)
- 組合實體模式(Composite Entity Pattern)
- 資料訪問物件模式(Data Access Object Pattern)
- 前端控制器模式(Front Controller Pattern)
- 攔截過濾器模式(Intercepting Filter Pattern)
- 服務定位器模式(Service Locator Pattern)
- 傳輸物件模式(Transfer Object Pattern)