程序上下文-Context(解釋別人沒有解釋的東西)

目錄

  • 大家理解的Context
  • 我的Context
  • 舉例子
  • 總結
  • 進階

大家理解的Context

搜索關鍵詞“程序上下文” “Context”,能搜到一些答案,但講得都不是很細,比如:

  • 維持一段程序正常運行的所需要的外部變量的值的集合,叫做上下文

    來自https://www.jianshu.com/p/6e07d31fa190

  • 用例子解釋不同場景下的意思:小美氣呼呼對我說:“你去死吧”,我當時就哭了

    來自https://blog.csdn.net/fenghuoliuxing990124/article/details/84502676

    講了很多, 不知道其他讀者是否領會了精神

我的Context

核心含義:上下文是完成一個邏輯涉及到的信息。

上下文需要區分程序上下文業務上下文

  • 程序上下文

    程序運行時,一個方法對應的數據空間,有一個專有名詞:棧幀、stack frame。他代表了方法可以訪問的數據。感興趣可以自己查一下。

  • 業務上下文

    這是一個抽象概念,我解釋的上下文傾向於業務上下文。業務上下文可以和程序上下文一致,也可以跨越程序上下文。

在實際使用的時候儘量讓業務上下文和程序上下文一致。

舉例子

  • 入參

    一個像someOne打招呼的代碼

    public void hello(String someOne) {
      System.out.println("Hello " + someOne)
    }
    

    上面代碼中hello方法就是一個邏輯,這個邏輯涉及到了需要向誰打招呼。

    業務上下文包含:someOne

    hello程序棧幀就是程序上下文,

    程序上下文包含:參數變量someOne

  • Local變量

    需求變成了連續hello兩次,代碼如下

    public void helloTwice(String someOne) {
      for (int i = 0; i < 2; i++) {
    	  System.out.println("Hello " + someOne)    
      }
    }
    

    業務上下文包含:someOne、當前執行次數i、需要執行次數2

    helloTwice程序棧幀就是程序上下文,

    程序上下文包含:someOne、當前執行次數i、需要執行次數2

  • 成員變量

    需求變成,每個人按照自己習慣的次數say hello。

    public class Person {
      private int habitHelloTime;
      public void hello(String someOne) {
        for (int i = 0; i < habitHelloTime; i++) {
          System.out.println("Hello " + someOne)    
        }
      }
    }
    

    業務上下文包含:someOne、當前執行次數i、habitHelloTime

    程序上下文包含:someOne、當前執行次數i、當前對象this

    雖然程序只是用到了this.habitHelloTime,但程序可以訪問整個對象this。此時程序上下文和業務上下文不完全一致。程序中Person只有一個成員,所以程序上下文和業務上下文差別不大。

  • 非靜態內部類訪問parent

    需求變化爲給someOne捎個話,所以延遲hello。

    public class Person {
      private int habitHelloTime;
    
      public void helloLater(String someOne) {
        threadPool.run(new Speaker(someOne));
      }
      
      private class Speaker {
        private String someOne;
        public void run() {
          for (int i = 0; i < habitHelloTime; i++) {
            System.out.println("Hello " + someOne)          
          }
        }
      }
    }
    

    業務上下文包含:someOne、當前執行次數i、habitHelloTime

    這裏有多個方法,涉及到多個程序上下文

    • helloLater程序上下文包括:someOne、threadPool、this(helloLater通過this創建了Speaker)
    • Speaker.run程序上下文包括:Speaker.this、Person.this和當前執行次數i。實際使用Speaker.this.someOne、Person.this.habitHelloTime和當前執行次數i

    這裏最接近業務上下文的程序上下文是Speaker.run,但是Speaker.run具有的訪問權限遠超他所需要的權限。

  • 全局

    需求沒有變,代碼也沒有變。補充一下,我們在代碼中順其自然的使用了System.out。這是一個全局信息,所有的邏輯都可以訪問到,使用起來很方便,但是他不在我們的業務範圍內,我們在表達業務邏輯時,默認使用了控制檯。

  • 進一步優化

    需求沒有變,只是修改了程序

    public class Person {
      private int habitHelloTime;
    
      public void helloLater(String someOne) {
        threadPool.run(new Speaker(someOne, habitHelloTime, System.out));
      }
    }
    private class Speaker {
      private String someOne;
      private int time;
      private PrintStream out;
      public void speak() {
        for (int i = 0; i < time; i++) {
          out.println("Hello " + someOne)          
        }
      }
    }
    

    業務上下文包含:someOne、當前執行次數i、habitHelloTime

    程序上下文包含:this.someOne、當前執行次數i、this.time、this.out

    這裏的業務只是按照個人方式向某人打招呼,通過什麼方式打招呼,並不在業務範圍內,所以業務上並沒有提出打招呼的方式,實現時也不能具體化爲System.out。

    現在的Speaker對象就是完整的業務上下文,同時包含了業務邏輯 。

總結

  • 核心含義:上下文是完成一個邏輯涉及到的信息。
  • 表現:代碼可以訪問到的東西。
  • 沒有邏輯,沒有上下文。如果沒有邏輯,也訪問到了,說明這個變量的作用域太大了

進階

這裏有一個更爲複雜的場景:讀書。

讀書邏輯:

1、開燈

2、讀書

3、關燈

  • 實現代碼如下:

    // 代碼A-1
    public class Person {
      public void readBook(String book) {
        openLight();
        lookBook(book);
        closeLight();
      }
    }
    

    業務上下文:書

    程序上下文:書

  • 實際業務中我們有很多燈,打開燈的時候會得到一個燈的ID,關閉也要關閉確定的燈

    // 代碼A-2
    public class Person {
      public void readBook(String book) {
        String lightId = openLight();
        lookBook(book);
        closeLight(lightId);
      }
    }
    

    業務上下文:燈、書

    程序上下文:燈、書

    這裏的lightId在readBook上下文中,它的作用域很小。也可以寫成另外的樣子

    // 代碼B-2
    public class Light {
      private String lightId;
      public void open();
      public void close();
    }
    public class Person {
      public void readBook(String book) {
        Light light = new Light();
        light.open();
        lookBook(book);
        light.close();
      }
    }
    

    根據上下文,抽象出了一個燈的對象。

    這裏的lightId在Light中,Light對象成爲一個關於燈的上下文,而light在readBook上下文中。

  • 現在還有一個情況,我們有很多燈,看書也應該在打開的燈下看,所以lookBook上下文也應該有lightId。

    下面有三種實現方式

    // 代碼A-3
    public class Person {
      public void readBook(String book) {
        String lightId = openLight();
        lookBook(book, lightId);
        closeLight(lightId);
      }
    }
    
    // 代碼B-3
    public class Light {
      private String lightId;
      public void open();
      public void close();
    }
    public class Person {
      public void readBook(String book) {
        Light light = new Light();
        light.open();
        lookBook(book, light.id);
        light.close();
      }
    }
    
    // 代碼C-3
    public class ReadBookContext {
      private String lightId;
      private String book;
    }
    public class Person {
      public void readBook(String book) {
        ReadBookContext context = new ReadBookContext(book);
        openLight(context);
        lookBook(context);
        closeLight(context);
      }
    }
    

    A、B、C三個方案都比較好的實現了這個邏輯

    • A:適合開燈關燈操作簡單,複用性不強的場景
    • B:適合開關燈邏輯複雜,可以複用,讀書場景涉及的動作比較少時
    • C:適合業務上下文內容很多時。當前只有兩個不明顯。

    到這裏大家可以看到讀書的業務上下文,在C中完全和程序上下文分家了。

    遇到複雜業務,通過上下文的方式可以有效解決擴展和傳參問題,提升可維護性。

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