新聞中心
這篇文章主要講解了“如何使用結(jié)構(gòu)型模式”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何使用結(jié)構(gòu)型模式”吧!
在成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站過(guò)程中,需要針對(duì)客戶(hù)的行業(yè)特點(diǎn)、產(chǎn)品特性、目標(biāo)受眾和市場(chǎng)情況進(jìn)行定位分析,以確定網(wǎng)站的風(fēng)格、色彩、版式、交互等方面的設(shè)計(jì)方向。創(chuàng)新互聯(lián)公司還需要根據(jù)客戶(hù)的需求進(jìn)行功能模塊的開(kāi)發(fā)和設(shè)計(jì),包括內(nèi)容管理、前臺(tái)展示、用戶(hù)權(quán)限管理、數(shù)據(jù)統(tǒng)計(jì)和安全保護(hù)等功能。
適配器模式
所謂適配器模式,就是把一個(gè)類(lèi)的結(jié)構(gòu)轉(zhuǎn)換成另外一個(gè)類(lèi)的接口。使得原本由于接口不兼容而不能工作的類(lèi)都能夠一起工作。
在生活中比較常見(jiàn)的就是當(dāng)我們想連接顯示器的時(shí)候,vga需要轉(zhuǎn)成hdmi,還有電源適配,比如可能需要220v的充電頭,但是只有110v的充電頭,那么就需要將220v的充電頭適配成110v的充電頭。
Adaptee:
需要適配的就代碼,舊接口
Adapter:
將調(diào)用轉(zhuǎn)發(fā)給Adaptee
的適配器類(lèi)
Target:
支持的新接口
適配器模式UML
類(lèi)適配器模式
Target
public interface Target { void output110v(); }
Adaptee
public class Adaptee { public void output220v() { System.out.println("輸出電壓"); } }
Adapter
public class Adapter extends Adaptee implements Target { @Override public void output110v() { this.output220v(); } }
這里需要注意的是Adapter
是繼承了源類(lèi)而實(shí)現(xiàn)了目標(biāo)類(lèi)
Client
public class Client { public static void main(String[] args) { Target target = new Adapter(); target.output110v(); } }
雖然我們是使用了output110v
的充電頭,但是經(jīng)過(guò)Adapter后,最終通過(guò)this.output220v()
會(huì)調(diào)用output220v
的充電頭,這就是把output220v
適配成了output110v
。
對(duì)象適配器模式
其實(shí)說(shuō)得這么高大上,其實(shí)就是Adaptor
的實(shí)現(xiàn)方式不同,類(lèi)適配器模式采用繼承了源類(lèi)(也就是需要適配的類(lèi))實(shí)現(xiàn)了目標(biāo)類(lèi)。
這樣就存在一個(gè)問(wèn)題,當(dāng)我們需要適配多個(gè)類(lèi)的時(shí)候就會(huì)出現(xiàn)問(wèn)題,因?yàn)閖ava中是允許實(shí)現(xiàn)多個(gè)接口,但是只能繼承一個(gè)類(lèi)。
為了解決這個(gè)問(wèn)題,我們可以把需要適配的類(lèi)作為Adapter
的成員變量,然后通過(guò)構(gòu)造函數(shù)進(jìn)行適配
public class NewAdapter implements Target{ Adaptee adaptee; public NewAdapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void output110v() { adaptee.output220v(); } }
代理模式
代理模式也算是比較常用的設(shè)計(jì)模式之一,大家接觸最多的spring aop,就是采用動(dòng)態(tài)代理模式來(lái)完成的。代理模式可以分為普通代理模式,強(qiáng)制代理模式,動(dòng)態(tài)代理模式,也是本文著重講解的,當(dāng)然還有其代理模式。
先來(lái)用一段代碼來(lái)體會(huì)代理模式,場(chǎng)景是玩家打游戲。
Subject:
共同接口,客戶(hù)端使用的現(xiàn)有接口
RealSubject:
真實(shí)對(duì)象的類(lèi)
ProxySubject:
代理對(duì)象類(lèi)
代理模式UML
普通代理模式
通過(guò)上面的例子,相信對(duì)大家都對(duì)代理模式有點(diǎn)感覺(jué)了,但是好像又不那么恰當(dāng),上面的測(cè)試類(lèi)種,還是需要新建一個(gè)player,這就相當(dāng)于什么,相當(dāng)于我們是在手機(jī)上登錄了游戲,然后再把手機(jī)給代練者代練。而事實(shí)上,經(jīng)常是把賬號(hào)密碼給代練即可。
這就引出了普通代理模式,客戶(hù)端不能訪問(wèn)真實(shí)角色,只能訪問(wèn)代理角色,我們能夠知道代理的存在。
Subject
public interface SubjectNormalGamePlayer { public void login(); public void upgrade(); public void matches(); }
RealSubject
public class RealSubjectNormalPlayerImpl implements SubjectNormalGamePlayer { private String name; private String password; public RealSubjectNormalPlayerImpl(String name, String password) { this.name = name; this.password = password; } @Override public void login() { if(name.equals("cutey") && password.equals("123456")) { System.out.println(name + "登錄成功"); } } @Override public void upgrade() { System.out.println(name + "升級(jí)"); } @Override public void matches() { System.out.println(name + "打排位賽"); } }
ProxySubject
public class ProxySubjectNormalPlayerImpl implements SubjectNormalGamePlayer { SubjectNormalGamePlayer gamePlayer; //注意這里的區(qū)別,我們是拿賬號(hào)和密碼去登錄真實(shí)角色 //并不是直接拿真實(shí)角色的手機(jī)來(lái)打 public ProxySubjectNormalPlayerImpl(String name, String password) { gamePlayer = new RealSubjectNormalPlayerImpl(name, password); } @Override public void login() { System.out.print("代練:"); gamePlayer.login(); } @Override public void upgrade() { System.out.print("代練:"); gamePlayer.upgrade(); } @Override public void matches() { System.out.print("代練:"); gamePlayer.matches(); } }
Client
public class Client { public static void main(String[] args) { //通過(guò)測(cè)試類(lèi)也很明顯區(qū)別,不必要顯示構(gòu)造真實(shí)角色類(lèi) SubjectNormalGamePlayer proxy = new ProxySubjectNormalPlayerImpl("cutey", "123456"); proxy.login(); proxy.upgrade(); proxy.matches(); } }
強(qiáng)制代理
普通代理呢是去找到一個(gè)代理對(duì)象幫打,但是強(qiáng)制代理呢,主要是體現(xiàn)在“強(qiáng)制”,角色類(lèi)會(huì)指定一個(gè)代理,其它方式找來(lái)的代理不能幫我打,一定要用我指定的代理才行。
Subject
和普通代理模式大部分代碼一樣,不同的是加了一個(gè)強(qiáng)制指定代理對(duì)象。
public interface SubjectForceGamePlayer { //省略登錄、升級(jí)和打排位等方法 //強(qiáng)制指定代理對(duì)象 public SubjectForceGamePlayer getForceProxy(); }
RealSubject
public class ForceGamePlayerImpl implements IForceGamePlayer { private String name; private String password; private IForceGamePlayer proxy = null; //指定需要誰(shuí)來(lái)代理 public ForceGamePlayerImpl(String name, String password) { this.name = name; this.password = password; } @Override public IForceGamePlayer getForceProxy() { //強(qiáng)制指定代理類(lèi),并且只有這樣才能給proxy賦值 proxy = new ForceProxyGamePlayerImpl(this); return proxy; } @Override public void login() { //只要不是自己指定的proxy,其它方式proxy肯定是null if(proxy != null) { if(name.equals("imperfect") && password.equals("123456")) { System.out.println(name + "登錄成功"); } } else { System.out.println("需要代理"); } } @Override public void upgrade() { if(proxy != null) { System.out.println(name + "升級(jí)"); } else { System.out.println("需要代理"); } } @Override public void matches() { if(proxy != null) { System.out.println(name + "打排位賽"); } else { System.out.println("需要代理"); } } }
ProxySubject
public class ProxySubjectForcePlayerImpl implements SubjectForceGamePlayer { private SubjectForceGamePlayer gamePlayer; //接收被代理對(duì)象的指定 public ProxySubjectForcePlayerImpl(SubjectForceGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } //省略登錄、升級(jí)和打比賽的方法 //沒(méi)有代理對(duì)象,暫時(shí)返回自己 @Override public SubjectForceGamePlayer getForceProxy() { return this; } }
Client
public class Client { public static void main(String[] args) { wrongProxy1(); wrongProxy2(); correctProxy(); } public static void correctProxy() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); //你這個(gè)代理必須是我指定的,并且強(qiáng)制要有 SubjectForceGamePlayer proxy = player.getForceProxy(); proxy.login(); proxy.upgrade(); proxy.matches(); } public static void wrongProxy1() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); SubjectForceGamePlayer proxy = new ProxySubjectForcePlayerImpl(player); proxy.login(); proxy.upgrade(); proxy.matches(); } public static void wrongProxy2() { SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456"); player.login(); player.upgrade(); player.matches(); } }
動(dòng)態(tài)代理
這個(gè)應(yīng)該是代理模式中用的比較多的,也是我覺(jué)得最需要各位小伙伴理解并且掌握的。所謂動(dòng)態(tài)代理是指,不用在編譯器指定為誰(shuí)代理,而是在運(yùn)行期再獲得被代理的對(duì)象并且執(zhí)行代理的方法。
下面將要講的例子是利用jdk中提供的InvocationHandler和Proxy類(lèi)
Subject
、RealSubject
都和普通代理模式一樣
ProxySubject
我們不知道要給誰(shuí)代理,所以要用到的是繼承InvocationHandler類(lèi)
public class ProxySubjectDynamicPlayerImpl implements InvocationHandler { Class cls = null; //要代理的類(lèi) Object obj = null; //需要代理的對(duì)象 //指定需要代理的對(duì)象 public ProxySubjectDynamicPlayerImpl(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //調(diào)用代理對(duì)象的方法 Object result = method.invoke(this.obj, args); if(method.getName().equalsIgnoreCase("login")) { System.out.println("異地登陸提醒:有人登錄我的賬戶(hù)"); } return result; } }
Client
public class Client { public static void main(String[] args) { SubjectDynamicPlayer player = new RealSubjectDynamicPlayerImpl("imperfect", "123456"); //把需要代理的信息交給handler,還記得invoke方法嗎 //在invoke方法中已經(jīng)實(shí)現(xiàn)了被代理對(duì)象的方法 InvocationHandler handler = new ProxySubjectDynamicPlayerImpl(player); //獲取被代理類(lèi)的類(lèi)加載屬性 ClassLoader cl = player.getClass().getClassLoader(); //獲取被代理類(lèi)的接口 Class[] interfaces = player.getClass().getInterfaces(); //把上述的三個(gè)信息交給Proxy創(chuàng)建出一個(gè)代理類(lèi) SubjectDynamicPlayer proxy = (SubjectDynamicPlayer) Proxy.newProxyInstance(cl, interfaces, handler); proxy.login(); proxy.upgrade(); proxy.matches(); } }
在編譯時(shí)我們是完全不知道給誰(shuí)代理,一切都是在運(yùn)行時(shí)才知道,這就是“動(dòng)態(tài)”
裝飾模式
裝飾模式就是動(dòng)態(tài)地給一個(gè)對(duì)象添加一些恩愛(ài)的職責(zé),就增加功能來(lái)說(shuō),裝飾模式比生成子類(lèi)更為靈活。
無(wú)論干什么,最重要的都是揚(yáng)長(zhǎng)避短,對(duì)于賣(mài)手機(jī)也是如此,肯定是把賣(mài)點(diǎn)詳細(xì)地介紹,而對(duì)于缺點(diǎn)能不提就不提。
Component:
定義一個(gè)對(duì)象的接口,可以給這些對(duì)象動(dòng)態(tài)地添加職責(zé)
ConcreteComponent:
具體的對(duì)象
Decorator:
裝飾抽象類(lèi),繼承了Component,從外類(lèi)來(lái)擴(kuò)展Component
ConcentrateDecorator:
具體的裝飾類(lèi)
裝飾模式UML
裝飾模式
Component
public abstract class ComponentMobile { //產(chǎn)品名字 private String name; //省略get,set,tostring方法 public abstract void showDetails(); public abstract void onSale(String userName); }
Concentrate Component
public class ConcreteComponentOnePlus extends ComponentMobile { public ConcreteComponentOnePlus(String name) { super(name); } @Override public void showDetails() { System.out.println("處理器:驍龍888 \r\n拍照:哈蘇專(zhuān)業(yè)模式 \r\n屏幕:2k+120hz 柔性屏 \r\n充電:65w快充"); } @Override public void onSale(String userName) { System.out.println(userName + "購(gòu)買(mǎi)了" + getName()); } }
Decorator
public abstract class Decorator extends ComponentMobile { //把要裝飾的手機(jī)拿給我 private ComponentMobile mobile; public Decorator(String name, ComponentMobile mobile) { super(name); this.mobile = mobile; } //細(xì)節(jié)還是要展示的 //只不過(guò)怎么展示呢,子類(lèi)可以加以修飾 public void showDetails() { mobile.showDetails(); } //手機(jī)也是要出售的 public void onSale(String name) { mobile.onSale(name); } }
注意,我們手機(jī)的細(xì)節(jié)還是要展示的,不能說(shuō)做的不好就不說(shuō)出來(lái),欺騙消費(fèi)者。能把你認(rèn)出來(lái)叫化妝,不能把你認(rèn)出來(lái)叫整容,我們講的是裝飾模式,不是整容模式。
Concrete Decorator
public class ConcreteDecoratorSystem extends Decorator { public ConcreteDecoratorSystem(String name, ComponentMobile mobile) { super(name, mobile); } //裝飾系統(tǒng) public void decorateScreen() { System.out.println("出廠配備了ColorOS,其它型號(hào)的手機(jī)也會(huì)逐步適配"); } @Override public void showDetails() { //想先介紹了系統(tǒng),再說(shuō)其他參數(shù) decorateScreen(); super.showDetails(); } }
public class ConcreteDecoratorPrice extends Decorator { public ConcreteDecoratorPrice(String name, ComponentMobile mobile) { super(name, mobile); } //公布價(jià)格 public void decoratePrice() { System.out.println("8 + 128:4999"); System.out.println("8 + 256: 5499"); } @Override public void showDetails() { super.showDetails(); //介紹完其它的后,公布性?xún)r(jià)比較高的價(jià)格 decoratePrice(); } }
Client
public class Client { public static void main(String[] args) { //手機(jī)發(fā)布會(huì),原產(chǎn)品 ComponentMobile mobile = new ConcreteComponentOnePlus("OnePlus 9 Pro"); //裝飾下系統(tǒng) mobile = new ConcreteDecoratorSystem(mobile.getName(), mobile); //裝飾下價(jià)格 mobile = new ConcreteDecoratorPrice(mobile.getName(), mobile); mobile.showDetails(); //用戶(hù)一看,誒,不錯(cuò)不錯(cuò),買(mǎi)了 mobile.onSale("cutey"); } }
感謝各位的閱讀,以上就是“如何使用結(jié)構(gòu)型模式”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何使用結(jié)構(gòu)型模式這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
新聞標(biāo)題:如何使用結(jié)構(gòu)型模式
本文路徑:http://fisionsoft.com.cn/article/jocjph.html