
我眼中的面向?qū)ο蠓治?/span>
面向?qū)ο?
似乎我也沒學(xué)過其他的編程思維方式了,面向?qū)ο笫俏揖幊虝r常用的思維方式,因為我覺得它更加貼近于我們的生活,更加容易地去理解和定義程序想要表達的內(nèi)容。正是因為如此,每當(dāng)項目要開啟的時候,我都會使用該種思維來分析和設(shè)計程序。多年下來發(fā)現(xiàn)它確實有著它的魅力,幫助我解決了很多設(shè)計中的問題。于是我總結(jié)了一下,在下面章節(jié)中說說面向?qū)ο笫褂蒙系囊恍┬牡谩?
給你的程序分“類”
面向?qū)ο蟮幕A(chǔ)就是“類”的設(shè)計,其設(shè)計好壞直接影響到程序的結(jié)構(gòu)。那么,如何才能設(shè)計出合理的類型呢?本人覺得應(yīng)該從實際需求出發(fā),提取需求中各種實體對象,最終形成程序中使用的對象。某些同學(xué)喜歡為自己的程序埋點,添加很多為日后作擴展的類型,其實我是不建議過度設(shè)計,我覺得可以在需求中提及的實體預(yù)留一些功能性的擴展,但是不建議為需求中沒有的功能點設(shè)計類型,因為,你永遠(yuǎn)都把握不準(zhǔn)產(chǎn)品日后的發(fā)展會是什么樣子的,最終形態(tài)是怎么樣,也有可能你埋下的點還沒來得及實現(xiàn),程序就需要進行重構(gòu)了等等的情況都會導(dǎo)致你的額外工作變成無用功。
假如公司要求你做一個附近的陌生人交友的App。從這個App的需求,可以提取出附近、陌生人以及交友三個關(guān)鍵字,附近描述的是一種相對的地理位置所以它應(yīng)該是一個類的屬性,而陌生人也是相對于某個人來說的一種人與人的關(guān)系,所以這里會被分解為一個人的實體,還有一個與其它人實體的關(guān)系。而最后一個交友關(guān)鍵字其實隱含了一種建立關(guān)系的行為,這里可以是聊天,也可以是其它的交友方式。我們再進一步分析,如果App里面提供了聊天功能,那么需求中還隱含了一個實體,那就是聊天的內(nèi)容。所以,根據(jù)需求這些點,我們可以設(shè)計出兩個類型:
這就由需求所驅(qū)動產(chǎn)生的類型,以這些類型為核心類圍繞需求進行補充和擴展來不斷滿足后續(xù)的需求。
讓類型也符合數(shù)據(jù)庫實體設(shè)計
關(guān)系數(shù)據(jù)庫設(shè)計中常會提及第三范式,其特點是去除表中直接依賴。這意思是說兩個實體對象不應(yīng)該被設(shè)計在同一個表中,如:評論表中有記錄是某個用戶發(fā)表的評論,可能會把用戶名稱等信息歸類到評論表中,那這樣是不符合第三范式要求的,正確的做法是把用戶信息放入用戶表,評論表中可以保留一個用戶id來標(biāo)識用戶表中的用戶記錄,從而取消在評論表中直接依賴用戶信息,導(dǎo)致用戶信息的冗余。
其實我個人覺得這種范式要求很好地劃分了實體之間的界線,對于類的設(shè)計也同樣適用。譬如:你定義了一個人類,該類型有四肢屬性和說話的行為。這樣很好理解,因為現(xiàn)實中人就具備這些特性。但是在后續(xù)的開發(fā)過程中由于需求的變動,出現(xiàn)了人類因為有飛行道具可以進行飛行。而把飛行的行為直接賦予人類,這種圖省事的做法其實是存在很多弊端的:
首先是不容易讀懂,因為常識性的認(rèn)為人是不會飛的,人會飛的話那肯定是個鳥人。所以會讓人摸不著頭腦。
再者就是這樣的定義往往會限制其它跟你協(xié)作開發(fā)的同事。因為大多數(shù)情況下我們都會秉持著能盡量不動舊代碼就不要去動,以免動出問題來。那么你這樣的設(shè)計就讓人不得不按照現(xiàn)有的思維去進行擴展。直到哪一天是在沒有辦法了,再進行徹底的重構(gòu)。
所以更優(yōu)的做法應(yīng)該是定義出一個道具類。至于道具實現(xiàn)什么功能,由其子類實現(xiàn):
// 道具基類
class Item
{
//道具的行為
function action(target : Person);
}
//飛行道具
class FlyingItem :Item
{
function action(target : Person)
{
//飛行的實現(xiàn)代碼
}
}
類似這樣的實現(xiàn)就可以分離人類和道具類型的耦合,而且也提高了道具類型的擴展。所以,在設(shè)計類型時一定要給實體分清界線。
另外一個數(shù)據(jù)庫設(shè)計時使用較多的就是實體的關(guān)系描述。實體的關(guān)系不同,在設(shè)計表存儲數(shù)據(jù)時也有所不同。通常有三種實體關(guān)系:
一對一,即兩個實體之間的關(guān)系是一一對應(yīng)的。如:一個中國公民跟他的身份證是唯一綁定的,知道身份證就能夠找到對應(yīng)的人,同樣對應(yīng)的人也能夠找到與其對應(yīng)的唯一的身份證。類似這種關(guān)系,通常是建立兩張實體數(shù)據(jù)表,然后關(guān)系可以同時放兩個實體表中。
一對多,即兩種實體之間,第一種實體可以對應(yīng)多個第二種實體,但是第二種實體只能對應(yīng)唯一的第一種實體。如用戶評論的例子,用戶可以發(fā)多條評論,但是一條評論只能夠是特定的一個用戶發(fā)出來。對于這種關(guān)系,通常也是建立兩張實體數(shù)據(jù)表,然后會在對應(yīng)多個實體的數(shù)據(jù)表中記錄關(guān)系,拿上面的例子來說,就是用戶表和評論表,然后評論表會放入一個userId之類的標(biāo)識來記錄與用戶的對應(yīng)關(guān)系。
多對多,即兩種實體之間,第一種實體可以對應(yīng)多個第二種實體,第二種實體也可以對應(yīng)多個第一種實體。例如作者和書籍的關(guān)系就是一種多對多的關(guān)系,一個作者可以寫多本書,同時,一本書有可能有多個作者共同寫成。對于這種關(guān)系,則需要建立兩種實體數(shù)據(jù)表以及一張關(guān)系表來進行描述。
說了這么多實體關(guān)系的東西,其實最想說的一點就是,在進行面向?qū)ο蠓治龊驮O(shè)計時,關(guān)系的分析也是不可缺少的。但是需要怎么來評估關(guān)系的劃分和歸屬,我覺得按照數(shù)據(jù)庫的關(guān)系設(shè)計標(biāo)準(zhǔn)來進行也是一種不錯的方法。
一對一,在該種關(guān)系下,其實關(guān)系的描述可以同時放在兩個類型上,如上面所說的中國公民與身份證的例子,用類可以描述為:
class Chinese
{
//姓名
property name:String;
//對應(yīng)的身份證
property idCard:IDCard;
}
class IDCard
{
//身份證號
property id:String;
//對應(yīng)的人
property person:Chinese;
}
一對多,該種關(guān)系下,稍微與數(shù)據(jù)庫表設(shè)計有點不同,由于數(shù)據(jù)表可以通過查詢的方式來找出實體對應(yīng)的多個另一種實體,這已經(jīng)超出了類設(shè)計階段的范疇。因此,對應(yīng)多個類實例的類型需要定義一個集合的屬性來保留對應(yīng)的多個類實例。這樣在閱讀代碼時也能夠很好理解,拿用戶評論的例子來說:
class User
{
property comments:Set<Comment>;
}
class Comment
{
property user:User;
}
類似這樣能夠很好的描述用戶進行過多少的評論,然后哪條評論是哪個用戶評論的。
多對多,這是一種很復(fù)雜的關(guān)系,主要是很多情況下,我們都會忽略這樣的一種關(guān)系,把它直接給變成了一對多的關(guān)系設(shè)計。其實對于種情況我們都可以將其關(guān)系的處理交由另外一個類型進行處理,與數(shù)據(jù)庫表設(shè)計一樣,兩個實體類型,一個關(guān)系類型。拿剛才作者跟書籍的關(guān)系為例,可以設(shè)計成下面的樣子:
//作者書籍關(guān)系管理類型
class AuthorBookRelationshipManager
{
//設(shè)置書籍的作者信息
static function setBookAuthor(book : Book, authors : Array<Author>) : void;
//獲取指定書籍的作者
static function getAuthors(book : Book) : Array<Author>;
//獲取指定作者的書籍
static function getBooks(author : Author) : Array<Book>;
}
//作者類型
class Author
{
//作者名稱
property name : String;
//獲取作者出版過的書籍
function getBooks() : Array<Book>
{
return AuthorBookRelationshipManager.getBooks(this);
}
}
//書籍類型
class Book
{
//書籍名稱
property name : String;
//獲取書籍的作者信息
function getAuthors():Array<Author>
{
return AuthorBookRelationshipManager.getAuthors(this);
}
}
上面的代碼可以看出,使用了一個AuthorBookRelationshipManager類型來管理書籍和作者的關(guān)系。然后實體類型不再保存之間的關(guān)系,要獲取相關(guān)的實體需要通過AuthorBookRelationshipManager類型來獲取。
上面所說的實體劃分和關(guān)系劃分在面向?qū)ο笾杏兄浅V匾囊饬x。平時要多加練習(xí)才能夠在面臨實際項目開發(fā)時做出合理的分類,讓自己開發(fā)的架構(gòu)更加靈活更加強大。
以上對于類型的設(shè)計基本上是講完了,是時候要說說繼承方面的事情了,這是面向?qū)ο蟮囊粋€很強大的特性。它可以改善代碼結(jié)構(gòu)的問題,節(jié)省代碼的書寫工作量。下面將會圍繞它來聊聊我的看法。
萬物的始祖
其實不管是寫C++、C#還是寫Java等等這些高級語言,我們都會發(fā)現(xiàn)只要是創(chuàng)建的類它們都會直接或者間接地繼承自O(shè)bject這個類。而這個Object類就是我這要說的萬物的始祖,其被所有的事物所繼承是一個根類型。Object這個名字也起得相當(dāng)好,泛指了所有的物體,給予了一種無形態(tài)的抽象的定義。意味著我們作為程序中的造物主,需要將這種無形態(tài)的物體,變化成各種具體形態(tài)的事物,這就需要繼承。
那么,Object中所做的功能其實并不多,因為它不涉及具體的功能,因此它很多時候在實現(xiàn)上面僅僅能區(qū)分是否是同一個對象isEqual,又或者是告訴我們它的描述toString。但是這樣已經(jīng)是有很大的引導(dǎo)意義,因為只要繼承了Object類型,那么你的類型將會得到這樣功能,闡述了繼承功能的強大;同時,你還可以把你的子類型對象賦予給一個Object的實例,因為Object是根類,它可以保留任意的子類類型對象,這是面向?qū)ο蠖鄳B(tài)的基本體現(xiàn)。
有了Object這樣的一個例子,更加表明了我們在開發(fā)項目過程中也應(yīng)該為項目的代碼設(shè)計基類。而這里的基類要比Object的功能稍微具體一點。因為它涉及到具體要實現(xiàn)的功能需求,而且還應(yīng)該不止是一個基類。下面來說一下我是怎么樣設(shè)計基類的。
和基類來個約定
要怎么設(shè)計基類,其實還是要根據(jù)實際的項目需求而定。假設(shè)你所開發(fā)的項目包含很多的后臺服務(wù),那么就應(yīng)該定義一個叫BaseService的基類,然后通過這個基類來分化成多種服務(wù)類型。如果你的項目涉及到多種UI的處理,那么你就應(yīng)該考慮可能需要一個基礎(chǔ)的UI管理類型(通常UI組件有自己的基類,這里需要的是對UI進行管理和維護的基礎(chǔ)類型),如:UIController。然后根據(jù)這個基類分化出各種的UI展現(xiàn)。
基本上是根據(jù)如果程序存在多種特性相近或相似的功能模塊,那么就應(yīng)該為這些模塊建立基類,以便日后更好的進行擴展。這里不建議要給未來有可能會有多種近似功能的模塊定義基類,還是老話,你的假設(shè)不一定成立。而且等到出現(xiàn)這樣的需求在進行定義也不遲,畢竟要改造的也只是一個類型而已。
上面我們知道如何去抽象出基類,那么基類應(yīng)該要如何封裝屬性和方法,其實完全可以視其子類而定,因為這樣是最貼近需求的。如前面所說的多種后臺服務(wù),假設(shè)有如下服務(wù)類型:
class ServiceA
{
//服務(wù)名稱
property name:String;
//調(diào)用服務(wù)
function exec(config:Dicationary):void
{
//執(zhí)行服務(wù)
}
}
class ServiceB
{
//服務(wù)名稱
property name:String;
//調(diào)用服務(wù)
function call():void
{
//執(zhí)行服務(wù)
}
}
上面所描述的服務(wù)從代碼結(jié)構(gòu)上面其實不大相同,特別是在執(zhí)行服務(wù)的行為上接收參數(shù)也不一樣。如果要從它們身上抽象出基類,確實會讓人有所困惑。但是,我們既然要抽象基類,那么就肯定會改造子類。我自己總結(jié)一些抽象的規(guī)則:
子類中相同的屬性和方法,要封裝到基類中。
對于大多數(shù)子類存在的屬性和方法(如5個子類中有3個以上類型存在相同的屬性和方法),可以考慮封裝到基類中,沒用到類型可以對基類的屬性和方法進行忽略。
對于意義相近的屬性,可以考慮將屬性合并或替換(如:子類中分別用id或者name屬性來表示對象的唯一,那么基類可以考慮只取其中一項屬性或者創(chuàng)建一個集合兩者的屬性定義)。
對于子類相同行為的方法,如果聲明的方法參數(shù)的數(shù)量或類型不同時,可以考慮基類的方法集合子類該方法中的所有參數(shù)(即取方法參數(shù)的并集)或者考慮定義共有參數(shù),特殊參數(shù)則由子類轉(zhuǎn)換為屬性來實現(xiàn)(一般可以持續(xù)持有的參數(shù)可以這樣設(shè)計,如系統(tǒng)的配置)。
基于上面所說的,我們可以把ServiceA和ServiceB,通過抽象基類改成下面的樣子:
class BaseService
{
//服務(wù)名稱
property name:String;
//調(diào)用服務(wù)
function exec():void;
}
class ServiceA extends BaseService
{
//這里將參數(shù)設(shè)定為屬性
property config:Dictionary;
function exec():void
{
//執(zhí)行服務(wù)
}
}
class ServiceB extends BaseService
{
function exec():void
{
//執(zhí)行服務(wù)
}
}
類似這樣,我們就可以把基類給抽象出來了。
讓類型進化
在開發(fā)和維護代碼的過程里面,難免會碰到由于產(chǎn)品的迭代,導(dǎo)致需求發(fā)生重大的變更。那么可能會出現(xiàn)某些功能的廢棄或者功能的合并或演進。這時候,之前定義的類型就要面臨著重構(gòu)或者調(diào)整的命運。
遇到這樣的問題我們先別急著把之前的東西全盤否定,然后徹底重寫。而是先考慮之前的定義中是否還存在可用的東西。要把可以重用的模塊給提取出來,那么,模塊的取舍就是我們需要評估的事情。
如果新的需求中已經(jīng)廢棄的功能,那么模塊所涉及的類型都可以進行廢棄。對于這些模塊的處理,我個人比較喜歡對相關(guān)的類型進行直接刪除,然后進行編譯,報錯后直接修改引用到該類型的代碼,直到編譯成功為止。對于缺失該類型后需要改造的方法,我會暫時不進行改造,而是打上標(biāo)記(如TODO或者warning宏),等待正式開發(fā)新功能時再尋找會這些標(biāo)記一一進行解決。
如果新需求中包含該類功能,但是又融合了一些新的元素,那么,我們的類型還不能直接拿來使用。要評估新的元素是否作為類型的一部分,還是作一種新的類型。例如:一款聊天應(yīng)用,剛開始的時候只有私聊(一對一聊天),那么,發(fā)送消息就在User類型中:
//用戶類型
class User
{
//給某個用戶發(fā)送消息
function sendMessage(user : User, message : Message) : void;
}
到了第二個版本的時候,可能支持用戶給好友群發(fā)消息。那么,明顯上面的代碼不能滿足需求,這時候需要對類型進行改造:
//用戶類型
class User
{
//給某個用戶發(fā)送消息
function sendMessage(user : User, message : Message) : void;
//給多個用戶發(fā)送消息
function sendMessage(users : Arrray<User>, message : Message) : void
{
for (User user in users)
{
this.sendMessage(user, message);
}
}
}
增加了一個sendMessage多態(tài)版本的方法用于群發(fā)消息。這樣既能保證方法的出口統(tǒng)一,又能保證之前的方法不被修改,就可以輕松地解決群發(fā)問題。
那么,到了第三個版本的時候出現(xiàn)了聊天室的概念,這時候需求中多了一個聊天室的關(guān)鍵字,運用之前提到的方法,這里應(yīng)該需要新增一個類型,不能直接在User類型中進行擴展。那么,可以設(shè)計為:
//聊天室
class ChatRoom
{
//聊天室名稱
property name:String;
//聊天室用戶
property users:Array<User>;
//發(fā)送消息
function sendMessage(user:User, message:Message):void;
}
這里增加了一個ChatRoom的類型,主要是用來記錄那些人在哪個聊天室中。該類型有一個sendMessage的方法,用于表示哪個用戶要在聊天室中發(fā)言,發(fā)言的內(nèi)容是什么。
由上面的例子可以看出來,產(chǎn)品迭代有時候需要讓類型進行,有時候也需要誕生新的類型。要做那種選擇則需要根據(jù)產(chǎn)品需求來決定。
只要這種多態(tài)
多態(tài)在我的理解中就是多種狀態(tài)。就好比我們用手拿東西的時候,如果拿的是球,那么我們可能是想要打球,如果拿的是蘋果,那么我們可能要把它吃掉。根據(jù)不同東西我們可能會作出不同的反映。在面向?qū)ο笾卸鄳B(tài)就是用于解決這類的問題。我們來假設(shè)一下沒有多態(tài)的時候,我們的代碼看起來會是多挫:
function doSomething(obj:Object):void
{
if (obj instanceof ObjectA)
{
//do something by ObjectA
}
else if (obj instanceof ObjectB)
{
//do something by ObjectB
}
}
要判斷的類型越多,if的語句就越長。那么有了多態(tài)后,我們可以很優(yōu)雅地設(shè)計:
function doSomething(obj:ObjectA):void
{
//do something by ObjectA
}
function doSomething(obj:ObjectB):void
{
//do something by ObjectB
}
多態(tài)可以保證代碼設(shè)計的出口名字統(tǒng)一,不需要外部調(diào)用的人要根據(jù)不同的類型調(diào)用不同名字的方法,對于外部調(diào)用只需要傳入的類型不同即可決定要調(diào)用哪個方法。
如果不是解決上面所說的問題,我不建議使用多態(tài)。因為多態(tài)會使到類型變得復(fù)雜,如果這個使用多態(tài)的類型被繼承,然后繼承的子類進行了多態(tài)處理,那么會影響到程序的質(zhì)量,并且一旦出現(xiàn)問題,排查的難度會有所增加。
后話
以上說的都是我個人在這些年的開發(fā)中所理解的東西,面向?qū)ο筮@東西已經(jīng)存在我腦海里面許多個日夜了,總想著寫些什么,今天總算把它給完成了。后續(xù)我會繼續(xù)寫下其他的一些關(guān)于程序思維的文章,希望大家支持。
寫這篇文章的時候沒有參考其他資料,可能存在錯漏的地方。如果你是一位好心的猿/媛,麻煩給我指正一下。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動態(tài)隨機一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計學(xué)領(lǐng)域,假設(shè)檢驗是驗證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實踐指南 在 Python 進行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點數(shù)據(jù)的科學(xué)計數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點數(shù)據(jù)時的科學(xué)計數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價值 在數(shù)據(jù)驅(qū)動決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實踐到業(yè)務(wù)價值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價值導(dǎo)向 統(tǒng)計模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10