訪問者模式場景
A. SElinux許可權
在了解SELinux之前,我們先來了解一下Linux的兩種訪問控制策略:DAC和MAC
DAC,自主訪問控制(Discretionary Access control)。系統只提供基本的驗證, 完整的訪問控制由開發者自己控制。
DAC將資源訪問者分成三類:Owner、Group、Other 。
將訪問許可權也分成三類:read、write、execute
資源針對資源訪問者設置不同的訪問許可權。訪問者通常是各個用戶的進程,有自己的uid/gid,通過uid/gid 和文件許可權匹配, 來確定是否可以訪問。DAC機制下,每一個用戶進程默認都擁有該用戶的所有許可權。
DAC 有兩個嚴重問題:
問題一:
因為Root用戶是擁有所有許可權的,所以DAC對Root用戶的限制是無效的。並且在Linux Kernel 2.1以後,Linux將Root許可權根據不同的應用場景劃分成許多的Root Capabilities, 普通用戶也可以被設置某個Root Capability。普通用戶如果被設置了CAP_DAC_OVERRIDE, 也可以繞過 DAC 限制。
問題二:
用戶進程擁有該用戶的所有許可權,可以修改/刪除該用戶的所有文件資源, 難以防止惡意軟體。
可見,DAC 有明顯的缺陷,一旦被入侵,取得Root許可權的用戶進程就可以無法無天,胡作非前滲行為,早期android版本就深受其害。
MAC, 強制性訪問控制(Mandatory Access control)。 系統針對每一項訪問都進行嚴格的限制, 具體的限制策略由開發者給出。
Linux MAC 針對DAC 的不足, 要求系統對每一項訪問, 每訪問一個文件資源都需要根據已經定義好了的策略進行針對性的驗證。系統可以針對特定的進程與特定的文件資源來進行許可權的控制。即使是root用戶,它所屬的不同的進程,並不一定能取得root許可權,而得要看事先為該進程定義的訪問限制策略。如果不能通過MAC 驗證,一樣無法執行相關的操作。
與DAC相比,MAC訪問控制的「主體」變成了「進程」而不是用戶。這樣可以限制了Root 許可權的濫用,另外要求對每一項許可權進行了更加完整的細化, 可以限制用戶對資源的訪問行為。
SELinux就是目前最好的MAC機制,也是目前的行業標准。
SELinux,安全增強Linux(Security-Enhanced Linux),是由美國國家安全局(NSA)發起, 多個非營利組織和高校參與開發的強制性安全審查機制(Mandatory Access control,簡稱MAC)。SELinux最早於2000年12月採用GPL許可發布。目前慧嘩,Linux Kernel 2.6 及以上的版本都已經集成了SELinux。
SELinux 分成三種模式:
Android 5.x及以上強制開啟,因此,disabled(關閉)模式並沒有什麼用了。 通常在調試時,我們會啟用Permissve(寬容模式), 以便盡可能的發現多的問題, 然後一次喊雀修正。 在量產時啟用Enfocing mode(強制模式)來保護系統。
查看SELinux模式:adb shell getenforce
設置SELinux模式:adb shell setenforce 1 //0是Permissve,1是Enfocing
SELinux 的訪問控制示意圖:
通常我們開發的過程中,就是配置Subject、Object、Security Policy。
SELinux 給Linux 的所有對象都分配一個安全上下文(Security Context), 描述成一個標準的字元串。
安全上下文的標准格式: user:role:type[:range]
Security Label 用來綁定被訪問資源和安全上下文,描述它們的對應關系。標准格式為:resource security_context。即:res user:role:type[:range]。這里也可以使用通配符,例如 net.就可以綁定所有以net.開頭的屬性,除此之外,還有類似正則表達式的*、?等等通配符。Security Label 都定義在type_contexts當中,例如file的定義在file_contexts中,service定義在service_contexts中,property定義在property_contexts中。
舉例:
file_contexts:
service_contexts:
查看進程安全上下文: ps -AZ 。例如,查看Settings進程的安全上下文,ps -AZ | grep settings:
u:r:system_app:s0 system 1381 585 4234504 201072 0 0 S com.android.settings
查看文件安全上下文: ls -Z 。例如,查看文件build.prop的安全上下文:
u:object_r:system_file:s0 build.prop
Type Enforcement (TE) 是根據Security Context中的 type 進行許可權審查, 審查 subject type 對 object type 的某個class 類型中某種permission 是否具有訪問許可權,是目前使用最為廣泛的MAC 審查機制, 簡單易用。
TE控制語句格式 : rule_name source_type target_type : class perm_set
Type Enforcement規則說明:
舉個例子,logd.te、tombstoned.te中定義的TE規則:
allow logd runtime_event_log_tags_file:file rw_file_perms;
dontaudit domain runtime_event_log_tags_file:file { open read };
auditallow tombstoned anr_data_file:file { append write };
neverallow logd { app_data_file system_data_file }:dir_file_class_set write;
SELinux 中每一個進程或者文件都對應一個type, 而每一個type 都對應有一個或幾個attribute。所有常見的attribute定義在以下文件中:
system/sepolicy/public/attributes
system/sepolicy/prebuilts/api/[build version]/public/attributes
system/sepolicy/prebuilts/api/[build version]/private/attributes
其中的[build version]即為android版本號,例如android O為28.0。常見的attribute定義:
Type對應一個或者幾個attribute,Type的定義格式:
type type_name, attribute1, attribute2;
Type的定義通常分散在各個te文件中。例如,常用普通文件的type定義在file.te中:
SEAndroid對於不同的資源類型,定義了不同的Class。比如普通的file、socket等等,比如SELinux 使用的security, 比如針對每個process 參數的process 等定義相關的class。這些class,每一個class 都有相對應的permissions。 比如file 就有 read, write, create, getattr, setattr, lock, ioctl 等等. 比如process 就有fork, sigchld, sigkill, ptrace, getpgid, setpgid 等等。這些相關的class, 以及他們具有那些Permissions都定義在以下文件中:
system/sepolicy/private/access_vectors
system/sepolicy/reqd_mask/access_vectors
system/sepolicy/prebuilts/api/版本號/private/access_vectors
例如:
定義完之後,在以下對應的security_classes 文件中聲明定義的classes。
system/sepolicy/private/security_classes
system/sepolicy/reqd_mask/security_classes
system/sepolicy/prebuilts/api/版本號/private/security_classes
例如:
注意,Classes 和Permissions的定義與Kernel 中相關API是強相關的,普通用戶嚴禁修改。
在SELinux 中, 我們通常稱一個進程是一個domain, 一個進程fork 另外一個進程並執行(exec) 一個執行檔時, 我們往往會涉及到domain 的切換. 比如init 進程, SELinux 給予了它很大的許可權, 而它拉起的服務, 我們要限制這個服務的許可權,於是就涉及到從一個domain 切換到另外一個domain, 不然默認就使用init 進程的domain.
在SELinux 裡面有專門的一條語法: type_transition statement.
在准備切換前我們先要確保有相關的許可權操作:
如下面的demo, init 拉起apache 並且切換到 apache 的domain.
(1). 首先,你得讓init_t域中的進程能夠執行type為apache_exec_t的文件
allow init_t apache_exec_t : file {read getattr execute};
(2). 然後,你還得告訴SELinux,允許init_t做DT切換以進入apache_t域
allow init_t apache_t : process transition;
(3). 然後,你還得告訴SELinux,切換入口(對應為entrypoint許可權)為執行apache_exec_t類型 的文件
allow apache_t apache_exec_t : file entrypoint;
(4).最後,Domain Transition
type_transition init_t apache_exec_t : process apache_t;
可以看到,整個domain切換過程寫起來非常麻煩。因此,Google 為了使用方便, 在system/sepolicy/public/te_macros 文件中定義了宏:
我們可以使用這些宏來完成domain切換。
舉例:
kernel啟動init進程切換domain:
domain_auto_trans(kernel, init_exec, init)
init啟動netd、vold、zygote、installd切換domain:
init_daemon_domain(netd)
init_daemon_domain(vold)
init_daemon_domain(zygote)
init_daemon_domain(installd)
一個進程創建在一個目錄下創建文件時, 默認是沿用父目錄的Security Context, 如果要設置成特定的Label, 就必須進行Object Transitions.
同樣是使用:type_transition statement.
對應的必須有兩個前提條件:
下面是一個demo, ext_gateway_t 這個domain 在類型為in_queue_t 的目錄下,創建類型為 in_file_t 的文件.
(1). 首先,你得讓ext_gateway_t 對in_queue_t 目錄具備訪問許可權
allow ext_gateway_t in_queue_t : dir { write search add_name };
(2). 然後,你還得告訴SELinux,允許ext_gateway_t 訪問in_file_t的文件
allow ext_gateway_t in_file_t : file { write create getattr };
(3).最後,Object Transition
type_transition ext_gateway_t in_queue_t : file in_file_t;
同樣的,為了方便使用,Google 也在system/sepolicy/public/te_macros 文件中定義了宏:
使用舉例:
file_type_auto_trans(factory, system_data_file, factory_data_file)
android O 以前sepolicy 集中放在boot image 。前面提到SELinux在Android的主要變更歷史時,有提到android O 開始,Google將system image 和 vendor image 分離。因此,sepolicy 也相應的被分離存放到system image 以及 vendor image。與system 相關的sepolicy 就存放system image, 與SoC vendor 相關的sepolicy 就存放在vendor image。
對於原生AOSP,Google 設定了不同的存放目錄, 以便進行分離, 以Google 默認的sepolicy 為例,sepolicy主目錄為 /system/sepolicy,我們主要關注三個子目錄:
對於不同的平台,不同平台廠商也設定了不同的存放目錄,以MTK平台為例:
首先,根據不同的platform共用sepolicy、platform獨有、project獨有,分為:
對應的,不同版本會導入不同目錄下的sepolicy配置
以mt6763平台為例,導入時:
[common] 路徑為:/device/mediatek/sepolicy
[platfrom] 路徑為:/device/mediatek/mt6763/sepolicy/
具體的定義在BoardConfig.mk文件中:
然後,basic、bsp、full又可以主要細分為:
Google 在system/sepolicy 中定義了相關的neverallow 規則, 對SELinux Policy 的更新進行了限制, 以防止開發者過度開放許可權,從而引發安全問題。並且還會通過CTS測試檢測開發者是否有違法相關的規則。
因此,我們需要注意以下幾點:
出現SELinux Policy Exception時常見的兩種解決方案:
(1). 修改對應節點的SELinux Security Label, 為特定的Subject,如system_app、platform_app、priv_app,例如Settings,SystemUI等內置APP開啟許可權, 但嚴禁為untrsted app 開啟許可權。
(2). 通過system server service 或者 init 啟動的service 讀寫操作, 然後app 通過binder/socket 等方式連接訪問. 此類安全可靠, 並且可以在service 中做相關的安全審查, 推薦這種方法.
情景: 定義由 init 進程啟動的service, factory, 其對應的執行檔是 /vendor/bin/factory。
(1). 在device/mediatek/mt6763/sepolicy/basic/non_plat 目錄下創建一個factory.te , 然後將te文件加入編譯,如放到這種指定目錄下不需要額外配置,sytem/sepolicy/Android.mk中定義的build_policy函數會遍歷指定目錄導入te文件。
(2). 在factory.te 中定義factory類型,init 啟動service 時類型轉換,
type factory, domain;
type factory_exec, exec_type, file_type, vendor_file_type;
init_daemon_domain(factory)
(3). 在file_contexts中綁定執行檔
/(system/vendor|vendor)/bin/factory u:object_r:factory_exec:s0
(4). 根據factory需要訪問的文件以及設備, 定義其它的許可權在factory.te 中.
#Purpose: For key and touch event
allow factory input_device:chr_file r_file_perms;
allow factory input_device:dir rw_dir_perms;
情景: 添加一個自定義的system property: persist.demo,並為platform_app設置讀寫許可權
(1). 在property.te中定義system property類型
type demo_prop, property_type
(2). 在property_contexts中綁定system property的安全上下文。
persist.demo u:object_r:demo_prop:s0
(3). 在platform_app.te 中新增寫許可權,可以使用set_prop宏。
set_prop(platform_app, demo_prop)
(4). 在platform_app.te 中新增讀許可權,可以get_prop 宏。
get_prop(platform_app, demo_prop)
情景: 有一個設備節點/dev/demo,有一個platform_app進程需要讀寫這個設備節點。
(1). 在device.te中定義device 類型
type demo_device dev_type;
(2). 在 file_contexts中綁定demo_device
/dev/demo u:object_r:demo_device:s0
(3). 在platform_app.te中,允許platform_app使用demo device 的許可權
allow platform_app demo_device:chr_file rw_file_perms;
情景: 有一個擴展的系統服務demo_service供APP調用。
(1). 在service.te 中定義service 類型
type demo_service, app_api_service, system_server_service, service_manager_type;
(2). 在service_contexts 中綁定service
demo u:object_r:demo_service:s0
(3). 在frameworks/base/core/java/android/content/Context.java中定義服務常量
public static final String DEMO_SERVICE = "demo";
(4). 在frameworks/base/core/java/android/app/SystemServiceRegistry.java中,參照其它系統服務注冊demo_service
(5). 在frameworks/base/services/java/com/android/server/SystemServer.java中,啟動DemoService,添加到service_manager進行管理。
(6). 最後一步,參考其它系統服務,實現DemoManager、DemoService,並定義如IDemoService等等的AIDL介面。
情景: 一個native service 通過init 創建一個socket 並綁定在 /dev/socket/demo, 並且允許某些process 訪問.
(1). 在file.te中定義socket 的類型
type demo_socket, file_type;
(2). 在file_contexts中綁定socket 的類型
/dev/socket/demo_socket u:object_r:demo_socket:s0
(3). 允許所有的process 訪問,使用宏unix_socket_connect(clientdomain, socket, serverdomain)
unix_socket_connect(appdomain, demo, demo)
(1). 在device/mediatek/mt6763/sepolicy/basic/non_plat目錄下創建一個demo.te。
(2). 在demo.te 中定義demo 類型,init 啟動service 時類型轉換。並可以根據demo 需要訪問的文件以及設備, 定義其它的許可權在demo.te 中。
type demo, domain;
type demo_exec, exec_type, file_type;
init_daemon_domain(demo)
(3). 綁定執行檔 file_context 類型
/vendor/bin/demo u:object_r:demo_exec:s0
(4). 創建demo的入口執行檔demo_exec、並配置相應的許可權。
(1). 將SELinux 調整到Permissive 模式復測
使用eng/userdebug 版本,adb shell setenforce 0 將SELinux 模式調整到Permissive 模式,然後復測。如果還能復現問題,則與SELinux 無關; 如果原本很容易復現, 而Permissive mode 不能再復現, 那麼就可能與SELinux相關。
(2). 查看LOG 中是否有標準的SELinux Policy Exception.
在Kernel LOG / Main Log 中查詢關鍵字 "avc: denied" 看看是否有與目標進程相關的SELinux Policy Exception, 並進一步確認這個異常是否與當時的邏輯相關。
一般情況我們在符合Google sepolicy策略及neverallow策略的前提下,根據LOG中的內容,需要什麼許可權就加什麼許可權。例如LOG:
2020-03-27 14:11:02.596 1228-1228/com.android.systemui W/FaceIdThread: type=1400 audit(0.0:481): avc: denied { read } for name="als_ps" dev="tmpfs" ino=10279 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:als_ps_device:s0 tclass=chr_file permissive=0
LOG說明如下:
一般我們需要重點關注的是四個:permission、source type、target type、target class
根據這四個就可以配置出的所需要的selinux許可權:
allow [source type] [target type]: [target class] [permission]
例1:
03-27 03:45:22.632 2958 2958 W Camera: type=1400 audit(0.0:314): avc: denied { read } for name="u:object_r:graphics_debug_prop:s0" dev="tmpfs" ino=2649 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:graphics_debug_prop:s0 tclass=file permissive=0
解決方案:
按正常的套公式,應該是這樣修改platform_app.te,增加:
allow platform_app graphics_debug_prop:file r_file_perms;
這里我們利用system/sepolicy/te_macros中定義的宏get_prop:
更多相關的宏定義請參考:system/sepolicy/public/te_macros。
所以最終簡化後,修改platform_app.te,增加:
get_prop(platform_app, graphics_debug_prop)
例2:
03-27 14:11:02.596 1228-1228/com.android.systemui W/BackThread: type=1400 audit(0.0:481): avc: denied { read } for name="als_ps" dev="tmpfs" ino=10279 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:als_ps_device:s0 tclass=chr_file permissive=0
解決方案:
修改platform_app.te增加:
allow platform_app als_ps_device:chr_file r_file_perms;
(1). 不符合neverallow規則或者修改了neverallow規則
編譯報錯:
neverallow check failed at xxx
CTS測試項failed:
android.cts.security.SELinuxNeverallowRulesTest#testNeverallowRulesXXX
這類問題在android O vendor和system分離之後,尤其容易出現。基本上這類問題都是因為修改或者增加的te配置不符合neverallow規則,導致編譯報錯。而為了解決編譯報錯,又修改了neverallow規則,最終在跑CTS時,沒法通過相關的測試項。
解決思路:
(2). init進程fork新進程沒有做domain切換
CTS測試項failed:
android.security.cts.SELinuxDomainTest # testInitDomain
解決思路:
fork進程時,參考3.4節中做domain切換。
本文主要參考了MTK-Online的Quick-start中《SELinux 問題快速分析》的內容,感謝原作者們的辛勤付出。另外,結合源碼和自身開發實踐,增加了一些自身理解和實踐內容。
B. 訪問者模式的優點
1、符合單一職責原則:凡是適用訪問者模式的場景中,元素類中需要封裝在訪問者中的操作必定是與元素類本身關系不大且是易變的操作,使用訪問者模式一方面符合單一職責原則,另一方面,因為被封裝的操作通常來說都是易變的,所以當發生變化時,就可以在不改變元素類本身的前提下,實現對變化部分的擴展。
2、擴展性良好:元素類可以通過接受不同的訪問者來實現對不同操作的擴展。
C. java中常用到得設計模式有哪幾種(java常用的設計模式及應用場景)
一共23種設計模式!
按照目的來分,設計模式可以分為創建型模式、結構型模式和行為型模式。
創建型模式用來處理對象的創建過程;結構型模式用來處理類或者對象的組合;行為型模式用來對類或對象怎樣交互和怎樣分配職責進行描述。
創建型模式用來處檔滲理對象的創建過程,主要包含以下5種設計模式:
工廠方法模式(FactoryMethodPattern)
抽象工廠模式(AbstractFactoryPattern)
建造者模式(BuilderPattern)
原型模式(PrototypePattern)
單例模式(SingletonPattern)
結構型模式用來處理類或者對象的組合,主要包含以下7種設計模式:
適配器模式(AdapterPattern)
橋接模式(BridgePattern)
組合模式(CompositePattern)
裝飾者模式(DecoratorPattern)
外觀模式(FacadePattern)
享元模式(FlyweightPattern)
代理模式(ProxyPattern)
行為型模式用來對類或對象怎樣交互和怎樣分配職責進行描述,主要包含以下11種設計模式:
責任鏈模式(行悉脊ChainofPattern)
命令模式(CommandPattern)
解釋器模式(InterpreterPattern)
迭代器模式(IteratorPattern)
中介者模式(MediatorPattern)
備忘錄模式(MementoPattern)
觀察者模陸旁式(ObserverPattern)
狀態模式(StatePattern)
策略模式(StrategyPattern)
模板方法模式(TemplateMethodPattern)
訪問者模式(VisitorPattern)
推薦你一本好書:《軟體秘笈:設計模式那點事》,裡面講解的23中設計模式例子很生動,容易理解,還有JDK中設計模式應用情況,看了收獲挺大的!網路裡面搜「設計模式」,第一條中設計模式網路中就有首推該圖書,瀏覽量在20幾萬以上的,不會錯的。好東西大家一起分享!
祝你早日學會設計模式!
D. 設計模式都有哪些
總體來說設計模式分為三大類:
一、創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
二、結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
三、行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
1、工廠方法模式:
定義一個用於創建對象的介面,讓子類決定實例化哪一個類。Factory Method 使一個類的實例化延遲到其子類。
工廠模式有一個問題就是,類的創建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,這就用到工廠方法模式。
創建一個工廠介面和創建多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的代碼。
2、抽象工廠模式:
提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。抽象工廠需要創建一些列產品,著重點在於"創建哪些"產品上,也就是說,如果你開發,你的主要任務是劃分不同差異的產品線,並且盡量保持每條產品線介面一致,從而可以從同一個抽象工廠繼承。
3、單例模式:
單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。這樣的模式有幾個好處:
(1)某些類創建比較頻繁,對於一些大型的對象,這是一筆很大的系統開銷。
(2)省去了new操作符,降低了系統內存的使用頻率,減輕GC壓力。
(3)有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以創建多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易伺服器獨立控制整個流程。
4、建造者模式:
將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
5、原型模式:
原型模式雖然是創建型的模式,但是與工程模式沒有關系,從名字即可看出,該模式的思想就是將一個對象作為原型,對其進行復制、克隆,產生一個和原對象類似的新對象。本小結會通過對象的復制,進行講解。在Java中,復制對象是通過clone()實現的,先創建一個原型類。
6、適配器模式:
適配器模式將某個類的介面轉換成客戶端期望的另一個介面表示,目的是消除由於介面不匹配所造成的類的兼容性問題。主要分為三類:類的適配器模式、對象的適配器模式、介面的適配器模式。
7、裝飾器模式:
顧名思義,裝飾模式就是給一個對象增加一些新的功能,而且是動態的,要求裝飾對象和被裝飾對象實現同一個介面,裝飾對象持有被裝飾對象的實例。
8、代理模式:
代理模式就是多一個代理類出來,替原對象進行一些操作,比如我們在租房子的時候回去找中介,為什麼呢?因為你對該地區房屋的信息掌握的不夠全面,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思。
9、外觀模式:
外觀模式是為了解決類與類之家的依賴關系的,像spring一樣,可以將類和類之間的關系配置到配置文件中,而外觀模式就是將他們的關系放在一個Facade類中,降低了類類之間的耦合度,該模式中沒有涉及到介面。
10、橋接模式:
橋接模式就是把事物和其具體實現分開,使他們可以各自獨立的變化。橋接的用意是:將抽象化與實現化解耦,使得二者可以獨立變化,像我們常用的JDBC橋DriverManager一樣。
JDBC進行連接資料庫的時候,在各個資料庫之間進行切換,基本不需要動太多的代碼,甚至絲毫不用動,原因就是JDBC提供統一介面,每個資料庫提供各自的實現,用一個叫做資料庫驅動的程序來橋接就行了。
11、組合模式:
組合模式有時又叫部分-整體模式在處理類似樹形結構的問題時比較方便。使用場景:將多個對象組合在一起進行操作,常用於表示樹形結構中,例如二叉樹,數等。
12、享元模式:
享元模式的主要目的是實現對象的共享,即共享池,當系統中對象多的時候可以減少內存的開銷,通常與工廠模式一起使用。
13、策略模式:
策略模式定義了一系列演算法,並將每個演算法封裝起來,使其可以相互替換,且演算法的變化不會影響到使用演算法的客戶。需要設計一個介面,為一系列實現類提供統一的方法,多個實現類實現該介面,設計一個抽象類(可有可無,屬於輔助類),提供輔助函數。
14、模板方法模式:
一個抽象類中,有一個主方法,再定義1...n個方法,可以是抽象的,也可以是實際的方法,定義一個類,繼承該抽象類,重寫抽象方法,通過調用抽象類,實現對子類的調用。
15、觀察者模式:
觀察者模式很好理解,類似於郵件訂閱和RSS訂閱,當我們瀏覽一些博客或wiki時,經常會看到RSS圖標,就這的意思是,當你訂閱了該文章,如果後續有更新,會及時通知你。
其實,簡單來講就一句話:當一個對象變化時,其它依賴該對象的對象都會收到通知,並且隨著變化!對象之間是一種一對多的關系。
16、迭代子模式:
顧名思義,迭代器模式就是順序訪問聚集中的對象,一般來說,集合中非常常見,如果對集合類比較熟悉的話,理解本模式會十分輕松。這句話包含兩層意思:一是需要遍歷的對象,即聚集對象,二是迭代器對象,用於對聚集對象進行遍歷訪問。
17、責任鏈模式:
責任鏈模式,有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發出者並不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。
18、命令模式:
命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開。
19、備忘錄模式:
主要目的是保存一個對象的某個狀態,以便在適當的時候恢復對象,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類A,A中有各種屬性,A可以決定需要備份的屬性,備忘錄類B是用來存儲A的一些內部狀態,類C呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操作。
20、狀態模式:
狀態模式在日常開發中用的挺多的,尤其是做網站的時候,我們有時希望根據對象的某一屬性,區別開他們的一些功能,比如說簡單的許可權控制等。
21、訪問者模式:
訪問者模式把數據結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用於數據結構相對穩定演算法又易變化的系統。因為訪問者模式使得演算法操作增加變得容易。
若系統數據結構對象易於變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增加新的數據結構很困難。
22、中介者模式:
中介者模式也是用來降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利於功能的拓展和維護,因為只要修改一個對象,其它關聯的對象都得進行修改。
如果使用中介者模式,只需關心和Mediator類的關系,具體類類之間的關系及調度交給Mediator就行,這有點像spring容器的作用。
23、解釋器模式:
解釋器模式一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。
(4)訪問者模式場景擴展閱讀:
介紹三本關於設計模式的書:
1、《設計模式:可復用面向對象軟體的基礎》
作者:[美] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
出版社: 機械工業出版社
2、《軟體秘笈:設計模式那點事》
作者:鄭阿奇
出版社:電子工業出版社
3、《設計模式:基於C#的工程化實現及擴展》
作者:王翔
出版社:電子工業出版社
E. CDP指的是什麼
什麼是CDP? David Raab 2013 年首次 提出了 (Customer Data Platform)CDP 的概念,其定義為:CDP 的目標是匯集所有客戶數據並 將數據存儲在統一的、可多部門訪問的數據平台中,讓企業各個部門都可 以輕松使用。
CDP是企業存儲的用戶數據的匯總中心,通過所有用戶數據的存儲,加工和處理後,將這些數據應用在用戶運營和業務驅動,最終提升企業盈利效率。