<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「補(bǔ)課」進(jìn)行時(shí):設(shè)計(jì)模式(18)——訪問(wèn)者模式

          共 5152字,需瀏覽 11分鐘

           ·

          2020-12-17 17:58

          1. 前文匯總

          「補(bǔ)課」進(jìn)行時(shí):設(shè)計(jì)模式系列

          2. 引言

          訪問(wèn)者模式也可以說(shuō)是所有設(shè)計(jì)模式中最難的一種設(shè)計(jì)模式了,當(dāng)然我們平常也很少會(huì)用到它。設(shè)計(jì)模式的作者是這么評(píng)價(jià)訪問(wèn)者模式的:大多情況下,你并不需要使用訪問(wèn)者模式,但是一旦需要使用它時(shí),那就真的需要使用了。

          3. 一個(gè)簡(jiǎn)單的示例

          又快到年底, CEO 和 CTO 開始評(píng)定員工一年的工作績(jī)效,員工分為工程師和經(jīng)理, CTO 關(guān)注工程師的代碼量、經(jīng)理的新產(chǎn)品數(shù)量;CEO 關(guān)注的是工程師的KPI和經(jīng)理的KPI以及新產(chǎn)品數(shù)量。

          由于 CEO 和 CTO 對(duì)于不同員工的關(guān)注點(diǎn)是不一樣的,這就需要對(duì)不同員工類型進(jìn)行不同的處理。訪問(wèn)者模式此時(shí)可以派上用場(chǎng)了。

          首先定義一個(gè)員工基類 Staff :

          public?abstract?class?Staff?{
          ????public?String?name;
          ????//?員工KPI
          ????public?int?kpi;

          ????public?Staff(String?name)?{
          ????????this.name?=?name;
          ????????kpi?=?new?Random().nextInt(10);
          ????}
          ????//?核心方法,接受Visitor的訪問(wèn)
          ????abstract?void?accept(Visitor?visitor);
          }

          Staff 類定義了員工基本信息及一個(gè) accept() 方法, accept() 方法表示接受訪問(wèn)者的訪問(wèn),由子類具體實(shí)現(xiàn)。

          Visitor 是個(gè)接口,傳入不同的實(shí)現(xiàn)類,可訪問(wèn)不同的數(shù)據(jù)。

          下面是工程師和經(jīng)理的具體實(shí)現(xiàn)類:

          public?class?Engineer?extends?Staff?{
          ????public?Engineer(String?name)?{
          ????????super(name);
          ????}
          ????@Override
          ????void?accept(Visitor?visitor)?{
          ????????visitor.visit(this);
          ????}
          ????//?工程師一年的代碼數(shù)量
          ????public?int?getCodeLines()?{
          ????????return?new?Random().nextInt(10?*?10000);
          ????}
          }

          public?class?Manager?extends?Staff?{
          ????public?Manager(String?name)?{
          ????????super(name);
          ????}
          ????@Override
          ????void?accept(Visitor?visitor)?{
          ????????visitor.visit(this);
          ????}
          ????//?一年做的產(chǎn)品數(shù)量
          ????public?int?getProducts()?{
          ????????return?new?Random().nextInt(10);
          ????}
          }

          工程師是代碼數(shù)量,經(jīng)理是產(chǎn)品數(shù)量,他們的職責(zé)不一樣,也就是因?yàn)椴町愋裕攀沟迷L問(wèn)模式能夠發(fā)揮它的作用。

          下面是 Visitor 接口的定義:

          public?interface?Visitor?{
          ????//?訪問(wèn)工程師類型
          ????void?visit(Engineer?engineer);
          ????//?訪問(wèn)經(jīng)理類型
          ????void?visit(Manager?manager);
          }

          Visitor 聲明了兩個(gè) visit 方法,分別是對(duì)工程師和經(jīng)理對(duì)訪問(wèn)函數(shù)。

          接下來(lái)定義兩個(gè)具體的訪問(wèn)者:CEO 和 CTO 。

          public?class?CEOVisitor?implements?Visitor?{
          ????@Override
          ????public?void?visit(Engineer?engineer)?{
          ????????System.out.println("工程師:?"?+?engineer.name?+?",?KPI:?"?+?engineer.kpi);
          ????}

          ????@Override
          ????public?void?visit(Manager?manager)?{
          ????????System.out.println("經(jīng)理:?"?+?manager.name?+?",?KPI:?"?+?manager.kpi?+?",?新產(chǎn)品數(shù)量:?"?+?manager.getProducts());
          ????}
          }

          public?class?CTOVisitor?implements?Visitor?{
          ????@Override
          ????public?void?visit(Engineer?engineer)?{
          ????????System.out.println("工程師:?"?+?engineer.name?+?",?代碼行數(shù):?"?+?engineer.getCodeLines());
          ????}

          ????@Override
          ????public?void?visit(Manager?manager)?{
          ????????System.out.println("經(jīng)理:?"?+?manager.name?+?",?產(chǎn)品數(shù)量:?"?+?manager.getProducts());
          ????}
          }

          接著是一個(gè)報(bào)表類,公司的 CEO 和 CTO 通過(guò)這個(gè)報(bào)表查看所有員工的業(yè)績(jī):

          public?class?BusinessReport?{
          ????private?List?mStaffs?=?new?LinkedList<>();
          ????public?BusinessReport()?{
          ????????mStaffs.add(new?Manager("經(jīng)理-A"));
          ????????mStaffs.add(new?Engineer("工程師-A"));
          ????????mStaffs.add(new?Engineer("工程師-B"));
          ????????mStaffs.add(new?Manager("經(jīng)理-B"));
          ????????mStaffs.add(new?Engineer("工程師-C"));
          ????}
          ????/**
          ?????*?為訪問(wèn)者展示報(bào)表
          ?????*?@param?visitor?公司高層,如?CEO、CTO
          ?????*/

          ????public?void?showReport(Visitor?visitor)?{
          ????????for?(Staff?staff?:?mStaffs)?{
          ????????????staff.accept(visitor);
          ????????}
          ????}
          }

          最后是一個(gè)場(chǎng)景類:

          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????//?構(gòu)建報(bào)表
          ????????BusinessReport?report?=?new?BusinessReport();
          ????????System.out.println("===========?CEO看報(bào)表?===========");
          ????????report.showReport(new?CEOVisitor());
          ????????System.out.println("===========?CTO看報(bào)表?===========");
          ????????report.showReport(new?CTOVisitor());
          ????}
          }

          執(zhí)行結(jié)果如下:

          ===========?CEO看報(bào)表?===========
          經(jīng)理:?經(jīng)理-A,?KPI:?7,?新產(chǎn)品數(shù)量:?8
          工程師:?工程師-A,?KPI:?6
          工程師:?工程師-B,?KPI:?3
          經(jīng)理:?經(jīng)理-B,?KPI:?4,?新產(chǎn)品數(shù)量:?4
          工程師:?工程師-C,?KPI:?2
          ===========?CTO看報(bào)表?===========
          經(jīng)理:?經(jīng)理-A,?產(chǎn)品數(shù)量:?6
          工程師:?工程師-A,?代碼行數(shù):?61280
          工程師:?工程師-B,?代碼行數(shù):?10353
          經(jīng)理:?經(jīng)理-B,?產(chǎn)品數(shù)量:?5
          工程師:?工程師-C,?代碼行數(shù):?65827

          4. 訪問(wèn)者模式

          4.1 定義

          訪問(wèn)者模式(Visitor Pattern) 是一個(gè)相對(duì)簡(jiǎn)單的模式, 其定義如下:

          Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. (封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作, 它可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。)

          4.2 通用類圖

          • Visitor 抽象訪問(wèn)者:抽象類或者接口,聲明訪問(wèn)者可以訪問(wèn)哪些元素。
          • ConcreteVisitor 具體訪問(wèn)者:它影響訪問(wèn)者訪問(wèn)到一個(gè)類后該怎么干, 要做什么事情。
          • Element 抽象元素:接口或者抽象類,聲明接受哪一類訪問(wèn)者訪問(wèn)。
          • ConcreteElement 具體元素:實(shí)現(xiàn)方法。
          • ObjectStruture 結(jié)構(gòu)對(duì)象:元素產(chǎn)生者,一般容納在多個(gè)不同類、不同接口的容器。

          4.3 通用代碼

          抽象元素:

          public?abstract?class?Element?{
          ????//?定義業(yè)務(wù)邏輯
          ????abstract?void?doSomething();
          ????//?定義允許訪問(wèn)角色
          ????abstract?void?accept(IVisitor?visitor);
          }

          具體元素:

          public?class?ConcreteElement1?extends?Element{
          ????@Override
          ????void?doSomething()?{

          ????}

          ????@Override
          ????void?accept(IVisitor?visitor)?{
          ????????visitor.visit(this);
          ????}
          }

          public?class?ConcreteElement2?extends?Element{
          ????@Override
          ????void?doSomething()?{

          ????}

          ????@Override
          ????void?accept(IVisitor?visitor)?{
          ????????visitor.visit(this);
          ????}
          }

          抽象訪問(wèn)者:

          public?interface?IVisitor?{
          ????void?visit(ConcreteElement1?ele1);
          ????void?visit(ConcreteElement2?ele2);
          }

          具體訪問(wèn)者:

          public?class?Visitor?implements?IVisitor{
          ????@Override
          ????public?void?visit(ConcreteElement1?ele1)?{
          ????????ele1.doSomething();
          ????}

          ????@Override
          ????public?void?visit(ConcreteElement2?ele2)?{
          ????????ele2.doSomething();
          ????}
          }

          結(jié)構(gòu)對(duì)象:

          public?class?ObjectStruture?{
          ????public?static?Element?createElement()?{
          ????????Random?random?=?new?Random();
          ????????if?(random.nextInt(100)?>?50)?{
          ????????????return?new?ConcreteElement1();
          ????????}?else?{
          ????????????return?new?ConcreteElement2();
          ????????}
          ????}
          }

          場(chǎng)景類:

          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????for?(int?i?=?0;?i?10;?i++)?{
          ????????????Element?e1?=?ObjectStruture.createElement();
          ????????????e1.accept(new?Visitor());
          ????????}
          ????}
          }

          4.4 優(yōu)點(diǎn)

          1. 各角色職責(zé)分離,符合單一職責(zé)原則。

            通過(guò)UML類圖和上面的示例可以看出來(lái),Visitor、ConcreteVisitor、Element 、ObjectStructure,職責(zé)單一,各司其責(zé)。

          2. 具有優(yōu)秀的擴(kuò)展性。

            如果需要增加新的訪問(wèn)者,增加實(shí)現(xiàn)類 ConcreteVisitor 就可以快速擴(kuò)展。

          3. 使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦,使得操作集合可以獨(dú)立變化。

            員工屬性(數(shù)據(jù)結(jié)構(gòu))和CEO、CTO訪問(wèn)者(數(shù)據(jù)操作)的解耦。

          4. 靈活性。

          4.5 缺點(diǎn)

          1. 具體元素對(duì)訪問(wèn)者公布細(xì)節(jié),違反了迪米特原則。

            CEO、CTO需要調(diào)用具體員工的方法。

          2. 具體元素變更時(shí)導(dǎo)致修改成本大。

            變更員工屬性時(shí),多個(gè)訪問(wèn)者都要修改。

          3. 違反了依賴倒置原則,為了達(dá)到「區(qū)別對(duì)待」而依賴了具體類,沒(méi)有用來(lái)抽象。

            訪問(wèn)者 visit 方法中,依賴了具體員工的具體方法。





          感謝閱讀



          瀏覽 21
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男人天堂无码视频 | 任我操在线视频 | 亚洲黄色视频网站免费在线观看 | 日本黄色免费网站 | 乱伦一级片 |