秒殺面試高頻SOLID和設計模式基礎


小哥哥,小姐姐們容我再打一波小廣告,我打算用幾年時間去做一份關於Java學習、面試、進階的GitHub項目。

👉GitHub地址:https://github.com/Ziphtracks/JavaLearningmanual

目前剛剛整理好JavaSE基礎內容,我將陸續的整理好JavaWeb階段以及框架知識體系,並添加完善到GitHub中,所以我希望大家能到我的GitHub給上一個Star !現在我的GitHub雖然還沒有完善多少技術文章,但是在幾個月後,我的GitHub也會陸續成爲一個完整的Java學習體系!

記得說好的Star哦!


一、什麼是設計模式?

軟件設計模式,簡稱設計模式。是一種可以被反覆使用、多人知曉、經過分類編目、代碼設計經驗的總結。簡單來說,就是一種經過精心考慮設計的代碼設計模板,我們可以使用該設計模板反覆套用,提高開發效率、代碼的可重用性、代碼的可讀性、代碼的可靠性,解決開發中的一系列問題!

二、爲什麼要學習設計模式?

設計模式的本質是面向對象設計原則的實際運用,是對類的封裝性、繼承性和多態性以及類的關聯關係和組合關係的充分理解。

使用設計模式的好處

  • 提高我們的邏輯思維、編程能力和設計能力。
  • 使程序設計更加標準化、代碼編制更加工程化,使軟件開發效率大大提高,從而縮短軟件的開發週期。
  • 使設計的代碼可重用性高、可讀性強、可靠性高、靈活性好、可維護性強。

三、設計模式的基本要素

3.1 設計模式的基本要素

設計模式的基本要素大致可以分爲四個主要部分:模式名稱、問題、解決方案和效果。

  • 模式名稱: 每一個模式都有自己的名稱,因爲我們需要根據模式的問題、特點、解決方案、功能和效果等要素來確定名稱,所以名稱能太長,一定要方便我們記憶、討論和設計。另外,模式名稱一定要有一擊必中的感覺,一個短短的詞就可以概括該設計模式的特點以及作用等等。
  • 問題: 要確定我們設計的設計模式適用於哪些反覆出現的應用環境。也就是哪些應用環境可以用到該設計模式來解決一系列問題。
  • 解決方案: 解決方案包括設計的組成成分、它們之間的相互關係及各自的職責和協作方式。因爲模式就像一個模板,可應用於多種不同場合,所以解決方案並不描述一個特定而具體的設計或實現,而是提供設計問題的抽象描述和怎樣用一個具有一般意義的元素組合(類或對象的 組合)來解決這個問題。
  • 效果: 採用該模式對軟件系統其他部分的時間、空間分析和影響(優缺點),比如對系統的擴充性、可移植性的影響。影響也包括負面的影響。

3.2 設計模式的其他要素

除了四個主要的基本要素外,還包括很多其他要素,比如:別名、動機、結構、模式角色、合作關係、實現方法、適用性、已知應用、例程、模式擴展和相關模式。

  • 別名: 一個模式可以有超過一個以上的名稱。這些名稱應該要在這一節註明。簡單來說,就像數據庫別名一樣,可以爲此模式取別名來方便記憶、映射其特點、作用等。
  • 動機: 該模式應用在哪種場景的情況下,也就是解決問題的動機是什麼?就在該環節提出問題與動機的設計。
  • 應用: 所謂應用,那就如其所意。映射該模式的應用場景以及如何應用等。
  • 結構: 就像設計一款軟件一樣,我們需要了解並設計它的結構。這裏常用類圖與互動圖闡述此模式的設計結構。
  • 模式角色: 提供在此次設計模式中的類與物件的清單,與它們在此設計模式中扮演的角色。
  • 合作: 在此設計模式中類與物件的互動與合作。
  • 結果: 描述使用該設計模式出現的結果,但是這裏結果也是分別好結果與壞結果的,甚至還描述了結果之間的交換問題。
  • 實現: 描述實現該模式、該模式的部分方案、實現該模式的可能技術、或者建議實現模式的方法。
  • 例程: 示範程式。
  • 已知應用: 業務已知的實做範例。
  • 相關模式: 相關模式包括其他相關模式,以及與其他類似模式的不同。

四、設計模式分類

設計模式類型可以分爲三類分別是創建型、結構型和行爲型設計模式。

類型 設計模式
創建型 工廠方法模式、生成器模式、抽象工廠模式、原型模式、單例模式
結構型 適配器(類)模式、橋接模式、容器模式、修飾模式、擴展性模式、外觀模式、享元模式、代理模式
行爲型 責任鏈模式、命令模式、解釋器模式、中介者模式、備忘錄模式、觀察者模式、狀態模式、策略模式、模板方法模式、訪問者模式

五、認識23種設計模式

  1. 單例(Singleton)模式: 某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
  2. 原型(Prototype)模式: 將一個對象作爲原型,通過對其進行復制而克隆出多個和原型類似的新實例。
  3. 工廠方法(Factory Method)模式: 定義一個用於創建產品的接口,由子類決定生產什麼產品。
  4. 抽象工廠(AbstractFactory)模式: 提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。
  5. 建造者(Builder)模式: 將一個複雜對象分解成多個相對簡單的部分,然後根據不同需要分別創建它們,最後構建成該複雜對象。
  6. 代理(Proxy)模式: 爲某對象提供一種代理以控制對該對象的訪問。即客戶端通過代理間接地訪問該對象,從而限制、增強或修改該對象的一些特性。
  7. 適配器(Adapter)模式: 將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類能一起工作。
  8. 橋接(Bridge)模式: 將抽象與實現分離,使它們可以獨立變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
  9. 裝飾(Decorator)模式: 動態的給對象增加一些職責,即增加其額外的功能。
  10. 外觀(Facade)模式: 爲多個複雜的子系統提供一個一致的接口,使這些子系統更加容易被訪問。
  11. 享元(Flyweight)模式: 運用共享技術來有效地支持大量細粒度對象的複用。
  12. 組合(Composite)模式: 將對象組合成樹狀層次結構,使用戶對單個對象和組合對象具有一致的訪問性。
  13. 模板方法(TemplateMethod)模式: 定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。
  14. 策略(Strategy)模式: 定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的改變不會影響使用算法的客戶。
  15. 命令(Command)模式: 將一個請求封裝爲一個對象,使發出請求的責任和執行請求的責任分割開。
  16. 職責鏈(Chain of Responsibility)模式: 把請求從鏈中的一個對象傳到下一個對象,直到請求被響應爲止。通過這種方式去除對象之間的耦合。
  17. 狀態(State)模式: 允許一個對象在其內部狀態發生改變時改變其行爲能力。
  18. 觀察者(Observer)模式: 多個對象間存在一對多關係,當一個對象發生改變時,把這種改變通知給其他多個對象,從而影響其他對象的行爲。
  19. 中介者(Mediator)模式: 定義一箇中介對象來簡化原有對象之間的交互關係,降低系統中對象間的耦合度,使原有對象之間不必相互瞭解。
  20. 迭代器(Iterator)模式: 提供一種方法來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。
  21. 訪問者(Visitor)模式: 在不改變集合元素的前提下,爲一個集合中的每個元素提供多種訪問方式,即每個元素有多個訪問者對象訪問。
  22. 備忘錄(Memento)模式: 在不破壞封裝性的前提下,獲取並保存一個對象的內部狀態,以便以後恢復它。
  23. 解釋器(Interpreter)模式: 提供如何定義語言的文法,以及對語言句子的解釋方法,即解釋器。

六、設計模式六大原則

注意: 前五個設計原則也屬於面向對象五大原則,簡稱“SOLID”。(面試中問到的SOLID就是它!)

設計原則名稱
單一職責原則:SRP(Single responsibility principle)
開放封閉原則/開閉原則:OCP(open close principl)
里氏替換原則:LSP(Liskov Substitution Principle)
接口隔離原則:ISP(Interface Segregation)
依賴倒置原則:DIP(Dependence Inversion Principle)
最少知道原則/迪米特法則:LoD(Law of Demeter)

七、分佈式剖析六大設計原則

7.1 單一職責原則

單一職責原則(SRP:Single responsibility principle)表示每個模塊、每個類、每個方法都只負責一件事情。

比如:SpringMVC只負責簡化MVC開發、Reader類只負責讀取文本文件內容、Math.round方法只負責四捨五入

單一職責原則思想演進步驟如下:

大家認識了單一職責原則,想必也知道其作用了。那我們試着寫一些代碼去證實一下單一職責原則的作用!

首先,我先寫一段代碼,如下:

public class Test {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;

        //求和
        int sum = num1 + num2;
        System.out.println(sum);//30

        //求積
        int product = num1 * num2;
        System.out.println(product);//200
    }
}

看到代碼的你們是不是覺得這個代碼太小兒科了,不就是相加求和和求數的乘積嘛,有什麼特別的。但是如果要求我們得出100、200和與乘積怎麼辦呢?我們延續這段代碼的話,就需要在再重新創建兩個變量分別存儲100和200,再分別求值,對不對。有沒有覺得很麻煩,如果要求我們寫100個數字分別求和和乘積呢?豈不是難上加難。

由此證明,該例子是一個反例。它破壞了單一職責原則,使代碼失去了複用性的特點,很多功能性代碼堆積在一起還顯得十分冗長,就單單這兩點就造成代碼的可讀性和複用性非常差!

聰明的小夥伴會說,我們封裝成方法啊。封裝成方法傳參不就好了嘛。是的,這纔是正解!

public class MathUtils {
    /**
     * 求和
     */
    public int getSum(int num1, int num2) {
        return num1 + num2;
    }

    /**
     * 求積
     */
    public int getProduct(int num1, int num2) {
        return num1 * num2;
    }
}

的確,入門級的兩段代碼就反映出來了單一職責原則的核心,那我們反過來考慮一下單一職責原則,是不是在我們的程序人生中隨處可見呢?小到我們封裝的各個方法,大到框架中的SpringMVC等都離不開單一職責原則的約束!

public class Test {
    public static void main(String[] args) {
        //求和
        System.out.println(MathUtils.getSum(100, 200));
        //求積
        System.out.println(MathUtils.getProduct(100, 200));
    }
}

7.2 開放封閉原則/開閉原則

開放封閉原則/開閉原則(OCP:open close principl)表示對功能擴展開放,對修改源碼關閉。

比如:軟件產品的更新換代、增加新功能。開發人員是非常忌諱去修改項目的源代碼的,因爲修改源代碼來實現產品的更新換代是一件非常危險而且造價極高的操作。所以,項目在架構中需要對功能擴展作以要求。

開閉原則思想演進步驟如下:

爲了模擬開閉原則,我們還是使用簡單易懂的代碼去映射。

首先,我們先創建一個產品實體類——Product

/**
 * 產品類
 */
public class Product {
    private String name;
    private Double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

其次,我們去寫一些對產品操作的代碼

public class Test {
    public static void main(String[] args) {
        Product iPhone = new Product();
		iPhone.setName=("iPhone11 Plus");
        iPhone.setPrice=(7000.00);
        
        Product huaWei = new Product();
        huaWei.setName("huaWei Mate30 Pro");
        huaWei.setPrice(8000.00);
        
        System.out.println(iPhone.getName() + " 價格:" + iPhone.getPrice());
        System.out.println(huaWei.getName() + " 價格:" + huaWei.getPrice());
    }
}

如果我們的蘋果公司和華爲公司同時搞活動,這兩個產品都打九折呢?於是,我們可以去修改Product實體類的get方法,如下:

public Double getPrice() {
    return price * 0.9;
}

修改後,我們蘋果手機和華爲手機都同時打了九折。如果這時候,蘋果公司先宣佈,我們的折扣活動到此爲止呢?但是華爲公司的折扣活動還在。我們該如何操作呢?所以,在這個時候就需要來糾正一下我們的思想了。首先,我們在此功能擴展(打折)過程中,不能去涉及修改源碼(修改實體類)的操作。其次,我們修改源碼並不能動態而普適性的解決問題!如果想解決遺留問題,請看如下代碼。

public class Discount extends Product{
    @Override
    public Double getPrice() {
        return super.getPrice() * 0.9;
    }
}
public class Test {
    public static void main(String[] args) {
        Product iPhone = new Discount();
        iPhone.setName("iPhone11 Plus");
        iPhone.setPrice(7000.00);
        
        System.out.println(iPhone.getName() + " 價格:" + iPhone.getPrice());
    }
}

爲了解決此問題,我們創建了一個打折的類——DIscount。然後重寫getPrice方法,並在此方法內做了打折操作,隨後使用多態的特性創建iPhone並賦予其參數。這樣以來,我們每次打折只需要修改打折類的getPrice方法即可,不需要修改其他的源代碼!

開發人員與用戶的關係:

在此,我們要知道產品時開發人員做出來的。當產品發佈新功能的時候,開發人員會對其產品做擴展。但是用戶想要新功能能隨便添加嗎?他們看得到源碼嗎?很明顯答案肯定爲false。所以在軟件的開發與使用過程中,開發人員與用戶各司其職,各自扮演者自己的角色,對誰都互不干擾!這就是所謂的開閉原則!

7.3 接口隔離原則

接口隔離原則(ISP:Interface Segregation)表示在開發中我們要面向多接口編程,而且一個類對另外一個類的依賴性應當是建立在最小的接口上的。一個接口代表一個角色,不應當將不同的角色都交給一個接口。沒有關係的接口合併在一起,形成一個臃腫的大接口,這是對角色和接口的污染。

接口隔離原則思想演進步驟如下:

其實很好理解,接口隔離原則在最初學習接口的時候,我們就知道了。只是當時不知道接口隔離原則這個名詞罷了!那我我寫一段代碼,演示給大家就明白了!

public interface Animal {
    void fly();

    void swim();
}

public class Bird implements Animal{
    @Override
    public void fly() {
        System.out.println("鳥在天空中飛來飛去");
    }

    @Override
    public void swim() {
        //因爲一般的鳥不會游泳,所以我們在這裏不做處理
    }
}

public class Fish implements Animal {
    @Override
    public void fly() {
        //因爲魚不會飛,我們在此不做處理
    }

    @Override
    public void swim() {
        System.out.println("魚在水中游來游去");
    }
}

public class Test {
    public static void main(String[] args) {
        Bird bird = new Bird();
        bird.fly();

        Fish fish = new Fish();
        fish.swim();
    }
}

在此代碼中,我們創建了一個Animal接口,裏面創建了動物的兩種特性,分別爲遊和飛。大家都知道普通的魚和鳥分別是遊和飛的。這時候我們就需要去實現Animal接口來創建所有方法並挑選其動物的特性再做處理。

這裏我們可以這麼分析。鳥和魚就是不同的角色,雖然它們都是屬於動物,但是它們各自擁有着不同的特性。顯然我們將不同的特性放在一個接口中很不合適,使用此接口變得臃腫,並對角色和接口造成了污染。

所以我們修改代碼,讓代碼變得好起來,如下操作:

public interface Fly {
    void fly();
}

public interface Swim {
    void swim();
}

public class Bird implements Fly{
    @Override
    public void fly() {
        System.out.println("鳥在天空中飛來飛去");
    }
}

public class Fish implements Swim {
    @Override
    public void swim() {
        System.out.println("魚在水中游來游去");
    }
}

public class Test {
    public static void main(String[] args) {
        Bird bird = new Bird();
        bird.fly();

        Fish fish = new Fish();
        fish.swim();
    }
}

修改操作,也就是去掉了Animal接口,然後創建了飛和遊的兩個接口,最後讓不同的動物去實現不同的特性接口即可。那如果動物有多特性,我們就多實現!

7.4 依賴倒置原則

依賴倒置原則(DIP:Dependence Inversion Principle)表示程序要依賴於抽象接口,不要依賴於具體 實現。簡單的說就是要求對抽象進行編程,不要對實現進行編程,這樣就降低了客戶與實現模塊 間的耦合。

依賴倒置原則思想演進步驟如下:

依賴倒置,就是角色之間的依賴關係發生的倒置現象,比如下例所示,貓、狗和奧特曼應該都是依賴於人的。但是在下例的代碼中,所看出的結果是人依賴於貓、狗、奧特曼。這樣如果人需要喂貓,我們就必須在Person類中創建喂貓的方法,那麼如果該人是一個動物園飼養員呢?那豈不是得喂成千上百種動物,那麼我們就必須在Person類中創建成千上百種的餵養方法嗎?答案肯定是false!

class Person {
    public void feedCat(Cat cat) {
        cat.eat();
    }

    public void feedDog(Dog dog) {
        dog.eat();
    }

    public void feedUltraMan(UltraMan ultraMan) {
        ultraMan.eat();
    }
}

class Cat {
    public void eat() {
        System.out.println("貓吃魚");
    }
}

class Dog {
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class UltraMan {
    public void eat() {
        System.out.println("奧特曼打小怪獸");
    }
}

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        Cat cat = new Cat();
        Dog dog = new Dog();
        UltraMan ultraMan = new UltraMan();
        person.feedCat(cat);
        person.feedDog(dog);
        person.feedUltraMan(ultraMan);
    }
}

所謂的依賴倒置原則,就是上述所說情景。爲了解決此現象的發生,我們需要如下操作!

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        Cat cat = new Cat();
        Dog dog = new Dog();
        UltraMan ultraMan = new UltraMan();
        person.feedAnimal(cat);
        person.feedAnimal(dog);
        person.feedAnimal(ultraMan);
    }
}

interface Animal {
    void eat();
}

class Person {
    public void feedAnimal(Animal animal) {
        animal.eat();
    }
}

class Cat implements Animal{
    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }
}

class Dog implements Animal{
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class UltraMan implements Animal{
    @Override
    public void eat() {
        System.out.println("奧特曼打小怪獸");
    }
}

解決此問題的所在就是一個核心接口。我們需要在上述代碼中,創建一個Animal動物接口,裏面寫一個eat方法。然後我們需要所有動物去實現此接口並覆蓋eat方法。而這時Person類中,我們就需要創建feedAnimal方法就好啦。通過傳參的方式就解決了在Person類中創建和修改過多的方法問題了,也就是解決了依賴倒置的問題。這次,你再考慮一下,是不是貓、狗和奧特曼都依賴於人呢?答案已經是顯而易見的了,肯定爲true!

7.5 里氏替換原則

里氏替換原則(LSP:Liskov Substitution Principle)表示任何父類可以出現的地方,子類一定可以出現。 LSP是繼承複用的基石,只有當子類可以替換掉父類,軟件單位的功能不受到影響時,父類才能真正被複用,而子類也能夠在父類的基礎上增加新的行爲。並且子類可以無障礙地替換父類。

里氏替換原則思想演進步驟如下:

首先,要知道我們在使用繼承的時候只會考慮一個子類“is a”另一個父類, 我們從來都沒有考慮過子類是否可以替換父類。其實在實際的開發中,我們要遵循里氏替換原則的,也就是上述的兩方面都必須考慮,這樣才能保證業務的完整性,並且不會發生改變。否則,就不能存在繼承關係。

也許有夥伴會不明白這裏的發生改變是什麼意思,後面的例子就會幫助解除你的疑惑!先看代碼!

/**
 * 長方形
 */
class Rectangle {
    private int width;
    private int height;

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Rectangle{" +
                "width=" + width +
                ", height=" + height +
                '}';
    }
}

/**
 * 正方形
 */
class Square extends Rectangle {
    //在給定寬的時候同時設置寬和高
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    //在給定高的時候同時設置寬和高
    @Override
    public void setHeight(int height) {
        super.setHeight(height);
        super.setWidth(height);
    }
}

public class Test {
    @org.junit.Test
    public void testRectangle() {
        Rectangle rectangle = new Rectangle();
        rectangle.setHeight(100);
        rectangle.setWidth(50);
        System.out.println(rectangle);
    }

    @org.junit.Test
    public void testSquare() {
        Square square = new Square();
        square.setHeight(50);
        System.out.println(square);
    }
}

這裏我創建了一個長方形和正方形,根據長方形寬高不一致的特性和正方形寬高(邊長)一致的特性,我們可以得出正方形“is a”長方形。簡單來說,根據它們的特性,正方形也是一個長方形。那我在代碼中,就將正方形繼承了長方形創建的寬高。對此傳入參數後,並沒有什麼異常現象出現。

但是,上述中我是不是強調了一個“發生改變”的字眼呢?那麼我們就試試唄,如果我們在特定情況下,只改變了長方形的寬,那請問它們兩個是繼承關係,正方形會怎樣呢?會不會發生異常現象呢?

請小夥伴們查看如下改變操作,注意reSize()方法:

/**
 * 長方形
 */
class Rectangle {
    private int width;
    private int height;

    public void reSize() {
        //如果高大於等於寬的話,我們就將寬在原來的基礎上增加1
        while (this.height >= this.width) {
            this.setWidth(this.getWidth() + 1);
        }
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Rectangle{" +
                "width=" + width +
                ", height=" + height +
                '}';
    }
}

/**
 * 正方形
 */
class Square extends Rectangle {
    //在給定寬的時候同時設置寬和高
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    //在給定高的時候同時設置寬和高
    @Override
    public void setHeight(int height) {
        super.setHeight(height);
        super.setWidth(height);
    }
}

public class Test {
    @org.junit.Test
    public void testRectangle() {
        Rectangle rectangle = new Rectangle();
        rectangle.setHeight(100);
        rectangle.setWidth(50);
        rectangle.reSize();
        System.out.println(rectangle);
    }

    @org.junit.Test
    public void testSquare() {
        Square square = new Square();
        square.setHeight(50);
        rectangle.reSize();
        System.out.println(square);
    }
}

代碼中我加了reSize方法在高大於寬的情況下,爲寬增加1,並將長方形和正方形同時在內部調用了reSize方法。在我們的測試過程中會發現,長方形的寬增加了1而變爲了51。但是正方形呢?正方形卻進入了一個死循環的狀態。這時候估計就有小夥伴來問爲什麼了?答案是因爲正方型的寬和高是相同的,而reSize方法內判斷的條件是>=關係,正方形正好符合=關係,所以也爲正方形改變寬+1的操作,但是正方形改變寬必須和高同時修改,這時候的修改卻不能做到這一點。所以正方形就陷入到了死循環的狀態而不能自拔。

綜上所述,我們在實際開發中考慮使用繼承的時候一定要遵循里氏替換原則,也就是考慮兩個方面。一、是否是“is a”關係;二、子類是否可以替換父類。如果兩個條件都符合的話,就可以使用繼承。否則,不能使用繼承關係!

7.6 最少知道原則/迪米特法則

最少知道原則/迪米特法則(LoD:Law of Demeter)表示一個對象應當對其他對象有儘可能少的瞭解,不和陌生人說話。

最少知道原則思想演進步驟如下:

最少知道原則,就想它的名字一樣,需要最少知道,也就是儘可能少的理解。在開發中保持的儘可能少理解的原則去寫代碼。爲什麼呢?看我舉一個例子,你就懂了。這大概是在考慮一些情況。比如如下例子:

我們在實際開發中,比如公司新招了一個員工。這時候,新員工需要了解我們的開發流程和進度。

這時候我用通俗易懂的方式來模擬這個場景,就像我們在開發中用電腦的時候,如果想要關閉電腦並關閉電源。我們的操作流程是先保存正在使用的數據、關閉屏幕和關閉電源。正如下所示:

注意:其實這個例子並不恰當,只是我約束了這個流程,來模擬事件而已,大家見諒!

public class Test {
    public static void main(String[] args) {
        CloseComputer closeComputer = new CloseComputer();
        closeComputer.saveData();
        closeComputer.turnOffScreen();
        closeComputer.turnOffHost();
    }
}

class CloseComputer {
    public void saveData() {
        System.out.println("保存數據");
    }

    public void turnOffScreen() {
        System.out.println("關閉屏幕");
    }

    public void turnOffHost() {
        System.out.println("關閉電源");
    }
}

假設上述代碼是一個正常的約束流程。我們需要保存數據、關閉屏幕和關閉電源。在這個流程中,我們的哪一個步驟都不能發生位置以及其他錯誤。這時候,我們招來的新員工並不熟悉該操作,這就有可能會造成數據的丟失,爲公司造成或大或小的損失。這時候,就算是我們需要知道的很多,才能正常、正確的跑完這個流程。所以,這時候我們要簡化這個流程,讓新員工知道很少的原則就可以實現。同時,再簡化流程的過程中,爲數據增加了一種保障,避免了誤操作的風險。

至於如何簡化流程,就看我編寫的如下代碼吧!

public class Test {
    public static void main(String[] args) {
        CloseComputer closeComputer = new CloseComputer();
        closeComputer.closeAll();
    }
}

class CloseComputer {
    public void closeAll() {
        saveData();
        turnOffScreen();
        turnOffHost();
    }

    public void saveData() {
        System.out.println("保存數據");
    }

    public void turnOffScreen() {
        System.out.println("關閉屏幕");
    }

    public void turnOffHost() {
        System.out.println("關閉電源");
    }
}

該操作,我將流程中的具體操作以正確的方式封裝在一個方法中,這時候我們的新員工不用知道過多的原則(簡化流程後),就可以正確的跑完流程。既爲新員工降低了壓力,又避免了數據丟失的風險。想想豈不是兩全其美!


記得GitHub一個Star哦!在此謝謝大家!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章