如何改進這段代碼

來源:互聯網
上載者:User
如下虛擬碼,
AService do2對P進行了操作,然後碰到的問題是PService裡對P進行操作,如果調用了AService do2那麼
由於不是對P最新的引用,save時會把AService do2的修改覆蓋掉。

//Update 2015年05月22日17:24:28
@Ke_Wu 這不應該是邏輯問題,事實上,我作為後來的調用者沒必要也不可能知道AService::do2裡的具體實現,但現在碰到問題了,那麼就是設計的問題了

class AService{    function do2(pid)    {        ...        p = P.getById(pid);        p.s = 'zz';        p.save();        ...    }}class PService{    function do1(pid)    {        ...        p = P.getById(pid);        p.s = 'yy';        AService.do2(pid);        ...        p.a = 'a';p.b = 'b';        ...        p.save();//p.s 仍舊是yy, zz被yy覆蓋        ...    }}class CService{    function do4(cid)    {        ...        c = C.getById(cid);        pid = c.pid;        AService.do2(pid);        ...    }}

回複內容:

如下虛擬碼,
AService do2對P進行了操作,然後碰到的問題是PService裡對P進行操作,如果調用了AService do2那麼
由於不是對P最新的引用,save時會把AService do2的修改覆蓋掉。

//Update 2015年05月22日17:24:28
@Ke_Wu 這不應該是邏輯問題,事實上,我作為後來的調用者沒必要也不可能知道AService::do2裡的具體實現,但現在碰到問題了,那麼就是設計的問題了

class AService{    function do2(pid)    {        ...        p = P.getById(pid);        p.s = 'zz';        p.save();        ...    }}class PService{    function do1(pid)    {        ...        p = P.getById(pid);        p.s = 'yy';        AService.do2(pid);        ...        p.a = 'a';p.b = 'b';        ...        p.save();//p.s 仍舊是yy, zz被yy覆蓋        ...    }}class CService{    function do4(cid)    {        ...        c = C.getById(cid);        pid = c.pid;        AService.do2(pid);        ...    }}

簡化下來其實問題就是:

phpp1 = P.getById(pid);p1.s = 'yy';...    p2 = P.getById(pid);    p2.s = 'zz';    p2.save();...p1.save();

儲存了p2的修改(可能是存到資料庫),並不意味著記憶體裡的p1隨之更新,除非你重新get一遍p1。
重構的目的是用來改善正確工作代碼的風格和設計。
這段代碼的問題是邏輯錯誤,對它而言談重構還為時過早。

你的問題的本質,是兩個“主語”(只是在你的案例中恰好都是service而已)的各自一個“行為”(do1 和 do2)含有了完全相同的一個“行動效果”(修改p.s的值)。
衝突不在於service,而在於行動效果冗餘。
試想一下,換一個案例,其中只有一個主語,兩個行為(do1 和 do2)都是它的,那麼問題也是等價的。
兩個行為有重疊的行動效果,實在太常見的了。
關鍵在於,你怎樣界定,哪種重疊是滿足需求的?哪種是錯誤、不合理的?

舉一個滿足需求的例子:
需求是:p是一個滑鼠移至上方的tips(介面組件)。先根據滑鼠座標,賦值p.top為一個值。隨後,計算tips是否超出了視窗邊緣。如果是,則計算tips的top的最大值(因為視窗大小可能會被改變,所以需要計算),然後賦值p.top為該最大值。p.left同理。
這是我做網頁前端開發時遇到過的需求。

你的解決辦法,大概可以解決你的那一個具體案例,但換成別的情況可能就又不對症了。
在我看來,關鍵在於,一個行為的源頭(往往是事件)所導致一連串列動效果,其中要避免出現重疊;除非需求要求必要的重疊。
這“一連串”的“串法”,是設計上要想清楚的。你已經在朝這個方向努力了,只是關注點稍有偏離。
至於串的過程中的對象(主語/賓語)是不是service、是何種service,倒是沒有關係。

我的解決辦法如下,有什麼缺點請指教:

Service應該分為2種:1,名詞Service; 2, 行為Service
如:UserService 與 RegisterService

對於【名詞Service】其裡面每個method都必須返回相應的對象,如UserService下的upgrade(uid)就必須返回被升級後的user對象。

對於【行為Service】只對外暴露出一個execute(data),excute(data)必須返回行為成功與否的狀態以及被施加這個行為的對象,如RegisterService下的excute(data)就必須返回註冊成功與否,以及如果成功了它影響的對象。

通常我們約定對外只調用【行為Service】,再在【行為Service】裡調用多個【名詞Service】和其他【行為Service】,如在RegisterService::execute(data)裡調用UserService::create(), UserService::markNewbee(uid),SendEmailService::execut()等;
【名詞Service】中不允許調用【行為Service】。

所有Service的每個method的入參都可以是id或者對象執行個體,如upgrade()可以接受uid也可以接受user作為入參。

回到我的提問,可以這麼寫

class AService{    function get(aid_or_object)    {        if (aid_or_object instanceOf A) {            return aid_or_object;        }        return A.getById(aid);    }}class PService{    function get(pid_or_object)    {        if (pid_or_object instanceOf P) {            return pid_or_object;        }        return P.getById(pid);    }}class Do2Service{    function execute(aid_or_object, pid_or_object = null)    {        a = AService.get(aid_or_object);        if (pid_or_object instanceOf P) {            p = pid_or_object        } else {            p = PService.get(a.pid);        }        p.s = 'zz';        p.save();        a.save();        return [:success, a, p];    }}class Do3Service{    function execute(pid_or_object)    {        p = PService.get(pid_or_object);        p.s = 'cc';        p.save();        return [:success, p];    }}class Do1Service{    function execute(pid_or_object)    {        p = PService.get(pid_or_object);        p.s = 'yy' if condition1                result, a, p = Do2Servce.execute(p.aid, p) if condition2        result, p = Do3Servce.execute(p) if condition3        p.a = 'a';        p.b = 'b';        p.save()        return [:success, p, a];    }}

想要解決什麼問題?

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.