1. 你所知道的設(shè)計(jì)模式有哪些
Java 中一般認(rèn)為有 23 種設(shè)計(jì)模式脖祈,我們不需要所有的都會(huì),但是其中常用的幾種設(shè)計(jì)模式應(yīng)該去掌握刷晋。下面列出了所有的設(shè)計(jì)模式盖高。需要掌握的設(shè)計(jì)模式我單獨(dú)列出來(lái)了慎陵,當(dāng)然能掌握的越多越好。
總體來(lái)說(shuō)設(shè)計(jì)模式分為三大類:
- 創(chuàng)建型模式喻奥,共五種:工廠方法模式席纽、抽象工廠模式、單例模式映凳、建造者模式、原型模式邮破。
- 結(jié)構(gòu)型模式诈豌,共七種:適配器模式、裝飾器模式抒和、代理模式矫渔、外觀模式、橋接模式摧莽、組合模式庙洼、享元模式。
- 行為型模式镊辕,共十一種:策略模式油够、模板方法模式、觀察者模式征懈、迭代子模式石咬、責(zé)任鏈模式、命令模式卖哎、備忘錄模式鬼悠、狀態(tài)模式、訪問(wèn)者模式亏娜、中介者模式焕窝、解釋器模式。
2. 單例設(shè)計(jì)模式
最好理解的一種設(shè)計(jì)模式维贺,分為懶漢式和餓漢式它掂。
餓漢式:
1. public class Singleton {
2. // 直接創(chuàng)建對(duì)象
3. public static Singleton instance = new Singleton();
4.
5. // 私有化構(gòu)造函數(shù)
6. private Singleton() {
7. }
8.
9. // 返回對(duì)象實(shí)例
10. public static Singleton getInstance() {
11. return instance;
12. }
13. }
優(yōu)點(diǎn):沒(méi)有并發(fā)問(wèn)題,只會(huì)產(chǎn)生一個(gè)Singleton對(duì)象溯泣;
缺點(diǎn):類初始化時(shí)就創(chuàng)建了對(duì)象群发,可能整個(gè)運(yùn)行過(guò)程都不會(huì)調(diào)用,占用內(nèi)存发乔。
懶漢式:
1. public class Singleton {
2. // 聲明變量
3. private static volatile Singleton singleton = null;
4.
5. // 私有構(gòu)造函數(shù)
6. private Singleton() {
7. }
8.
9. // 提供對(duì)外方法
10. public static Singleton getInstance() {
11. if (singleton == null) {
12. synchronized (Singleton.class) {
13. if (singleton == null) {
14. singleton = new Singleton();
15. }
16. }
17. }
18. return singleton;
19. }
20. }
優(yōu)點(diǎn):使用時(shí)才會(huì)創(chuàng)建對(duì)象熟妓,避免了占用內(nèi)存的問(wèn)題;
缺點(diǎn):使用synchronized解決并發(fā)問(wèn)題(如果不用synchronized會(huì)有并發(fā)問(wèn)題)栏尚,則會(huì)影響效率起愈。
3. 工廠設(shè)計(jì)模式
工廠模式分為工廠方法模式和抽象工廠模式。
- 工廠方法模式
工廠方法模式分為三種:
- 普通工廠模式,就是建立一個(gè)工廠類抬虽,對(duì)實(shí)現(xiàn)了同一接口的一些類進(jìn)行實(shí)例的創(chuàng)建官觅。
- 多個(gè)工廠方法模式,是對(duì)普通工廠方法模式的改進(jìn)阐污,在普通工廠方法模式中休涤,如果傳遞的字符串出錯(cuò),則不能正確創(chuàng)建對(duì)象笛辟,而多個(gè)工廠方法模式是提供多個(gè)工廠方法功氨,分別創(chuàng)建對(duì)象。
- 靜態(tài)工廠方法模式手幢,將上面的多個(gè)工廠方法模式里的方法置為靜態(tài)的捷凄,不需要?jiǎng)?chuàng)建實(shí)例,直接調(diào)用即可围来。
普通工廠模式
1. public interface Sender {
2. public void Send();
3. }
4. public class MailSender implements Sender {
5.
6. @Override
7. public void Send() {
8. System.out.println("this is mail sender!");
9. }
10. }
11. public class SmsSender implements Sender {
12.
13. @Override
14. public void Send() {
15. System.out.println("this is sms sender!");
16. }
17. }
18. public class SendFactory {
19. public Sender produce(String type) {
20. if ("mail".equals(type)) {
21. return new MailSender();
22. } else if ("sms".equals(type)) {
23. return new SmsSender();
24. } else {
25. System.out.println("請(qǐng)輸入正確的類型!");
26. return null;
27. }
28. }
29. }
多個(gè)工廠方法模式
該模式是對(duì)普通工廠方法模式的改進(jìn)跺涤,在普通工廠方法模式中,如果傳遞的字符串出錯(cuò)监透,則不能正確創(chuàng)建對(duì)象桶错,而多個(gè)工廠方法模式是提供多個(gè)工廠方法,分別創(chuàng)建對(duì)象胀蛮。
1. public class SendFactory {
2. public Sender produceMail(){
3. return new MailSender();
4. }
5.
6. public Sender produceSms(){
7. return new SmsSender();
8. }
9. }
10.
11. public class FactoryTest {
12. public static void main(String[] args) {
13. SendFactory factory = new SendFactory();
14. Sender sender = factory.produceMail();
15. sender.send();
16. }
17. }
靜態(tài)工廠方法模式牛曹,將上面的多個(gè)工廠方法模式里的方法置為靜態(tài)的,不需要?jiǎng)?chuàng)建實(shí)例醇滥,直接調(diào)用即可黎比。
1. public class SendFactory {
2. public static Sender produceMail(){
3. return new MailSender();
4. }
5.
6. public static Sender produceSms(){
7. return new SmsSender();
8. }
9. }
10.
11.
12. public class FactoryTest {
13. public static void main(String[] args) {
14. Sender sender = SendFactory.produceMail();
15. sender.send();
16. }
17. }
- 抽象工廠模式
工廠方法模式有一個(gè)問(wèn)題就是,類的創(chuàng)建依賴工廠類鸳玩,也就是說(shuō)阅虫,如果想要拓展程序,必須對(duì)工廠類進(jìn)行修
改不跟,這違背了閉包原則颓帝,所以,從設(shè)計(jì)角度考慮窝革,有一定的問(wèn)題购城,如何解決?就用到抽象工廠模式虐译,創(chuàng)建多個(gè)工廠類瘪板,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了漆诽,不需要修改之前的代碼侮攀。
1. public interface Provider {
2. public Sender produce();
3. }
4. -------------------------------------------------------------------------------------
5. public interface Sender {
6. public void send();
7. }
8. -------------------------------------------------------------------------------------
9. public class MailSender implements Sender {
10.
11. @Override
12. public void send() {
13. System.out.println("this is mail sender!");
14. }
15. }
16. -------------------------------------------------------------------------------------
17. public class SmsSender implements Sender {
18.
19. @Override
20. public void send() {
21. System.out.println("this is sms sender!");
22. }
23. }
24. -------------------------------------------------------------------------------------
25. public class SendSmsFactory implements Provider {
26.
27. @Override
28. public Sender produce() {
29. return new SmsSender();
30. }
31. }
1. public class SendMailFactory implements Provider {
2.
3. @Override
4. public Sender produce() {
5. return new MailSender();
6. }
7. }
8. -------------------------------------------------------------------------------------
9. public class Test {
10. public static void main(String[] args) {
11. Provider provider = new SendMailFactory();
12. Sender sender = provider.produce();
13. sender.send();
14. }
15. }
4. 建造者模式(Builder)
工廠類模式提供的是創(chuàng)建單個(gè)類的模式锣枝,而建造者模式則是將各種產(chǎn)品集中起來(lái)進(jìn)行管理,用來(lái)創(chuàng)建復(fù)合對(duì)象兰英,所謂復(fù)合對(duì)象就是指某個(gè)類具有不同的屬性撇叁,其實(shí)建造者模式就是前面抽象工廠模式和最后的 Test 結(jié)合起來(lái)得到的。(意思大概是工廠模式每次只會(huì)返回一種特定的對(duì)象畦贸,但是使用建造者模式陨闹,可以返回多種實(shí)現(xiàn)同一接口的不同實(shí)現(xiàn)類對(duì)象,就像建大樓薄坏,我需要材料趋厉,工廠方法每次就只送磚或其它某一種材料;但是通過(guò)建造者模式送磚及其混泥土等一堆材料)
1. public class Builder {
2. private List<Sender> list = new ArrayList<Sender>();
3.
4. public void produceMailSender(int count) {
5. for (int i = 0; i < count; i++) {
6. list.add(new MailSender());
7. }
8. }
9.
10. public void produceSmsSender(int count) {
11. for (int i = 0; i < count; i++) {
12. list.add(new SmsSender());
13. }
14. }
15. }
1. public class TestBuilder {
2. public static void main(String[] args) {
3. Builder builder = new Builder();
4. builder.produceMailSender(10);
5. }
6. }
5. 適配器設(shè)計(jì)模式
適配器模式將某個(gè)類的接口轉(zhuǎn)換成客戶端期望的另一個(gè)接口表示颤殴,目的是消除由于接口不匹配所造成的類的兼容性問(wèn)題觅廓。主要分為三類:類的適配器模式鼻忠、對(duì)象的適配器模式涵但、接口的適配器模式。
- 類的適配器模式
1. public class Source {
2. public void method1() {
3. System.out.println("this is original method!");
4. }
5. }
6. -------------------------------------------------------------
7. public interface Targetable {
8. /* 與原類中的方法相同 */
9. public void method1();
10. /* 新類的方法 */
11. public void method2();
12. }
13. public class Adapter extends Source implements Targetable {
14. @Override
15. public void method2() {
16. System.out.println("this is the targetable method!");
17. }
18. }
19. public class AdapterTest {
20. public static void main(String[] args) {
21. Targetable target = new Adapter();
22. target.method1();
23. target.method2();
24. }
25. }
- 對(duì)象的適配器模式
基本思路和類的適配器模式相同帖蔓,只是將 Adapter 類作修改矮瘟,這次不繼承 Source 類,而是持有 Source 類的實(shí)例塑娇,以達(dá)到解決兼容性的問(wèn)題澈侠。
1. public class Wrapper implements Targetable {
2. private Source source;
3.
4. public Wrapper(Source source) {
5. super();
6. this.source = source;
7. }
8.
9. @Override
10. public void method2() {
11. System.out.println("this is the targetable method!");
12. }
13.
14. @Override
15. public void method1() {
16. source.method1();
17. }
18. }
19. --------------------------------------------------------------
20. public class AdapterTest {
21.
22. public static void main(String[] args) {
23. Source source = new Source();
24. Targetable target = new Wrapper(source);
25. target.method1();
26. target.method2();
27. }
28. }
- 接口的適配器模式
接口的適配器是這樣的:有時(shí)我們寫(xiě)的一個(gè)接口中有多個(gè)抽象方法,當(dāng)我們寫(xiě)該接口的實(shí)現(xiàn)類時(shí)埋酬,必須實(shí)現(xiàn)該接口的所有方法哨啃,這明顯有時(shí)比較浪費(fèi),因?yàn)椴⒉皇撬械姆椒ǘ际俏覀冃枰男赐祝袝r(shí)只需要某一些拳球,此處為了解決這個(gè)問(wèn)題,我們引入了接口的適配器模式珍特,借助于一個(gè)抽象類祝峻,該抽象類實(shí)現(xiàn)了該接口,實(shí)現(xiàn)了所有的方法扎筒,而我們不和原始的接口打交道莱找,只和該抽象類取得聯(lián)系,所以我們寫(xiě)一個(gè)類嗜桌,繼承該抽象類奥溺,重寫(xiě)我們需要的方法就行。
6. 裝飾模式(Decorator)
顧名思義骨宠,裝飾模式就是給一個(gè)對(duì)象增加一些新的功能谚赎,而且是動(dòng)態(tài)的淫僻,要求裝飾對(duì)象和被裝飾對(duì)象實(shí)現(xiàn)同一個(gè)接口,裝飾對(duì)象持有被裝飾對(duì)象的實(shí)例壶唤。
1. public interface Sourceable {
2. public void method();
3. }
4. ----------------------------------------------------
5. public class Source implements Sourceable {
6. @Override
7. public void method() {
8. System.out.println("the original method!");
9. }
10. }
11. ----------------------------------------------------
12. public class Decorator implements Sourceable {
13. private Sourceable source;
14. public Decorator(Sourceable source) {
15. super();
16. this.source = source;
17. }
18.
19. @Override
20. public void method() {
21. System.out.println("before decorator!");
22. source.method();
23. System.out.println("after decorator!");
24. }
25. }
26. ----------------------------------------------------
27. public class DecoratorTest {
28. public static void main(String[] args) {
29. Sourceable source = new Source();
30. Sourceable obj = new Decorator(source);
31. obj.method();
32. }
33. }
7. 策略模式(strategy)
策略模式定義了一系列算法雳灵,并將每個(gè)算法封裝起來(lái),使他們可以相互替換闸盔,且算法的變化不會(huì)影響到使用算法的客戶悯辙。需要設(shè)計(jì)一個(gè)接口,為一系列實(shí)現(xiàn)類提供統(tǒng)一的方法迎吵,多個(gè)實(shí)現(xiàn)類實(shí)現(xiàn)該接口躲撰,設(shè)計(jì)一個(gè)抽象類(可有可無(wú),屬于輔助類)击费,提供輔助函數(shù)拢蛋。策略模式的決定權(quán)在用戶,系統(tǒng)本身提供不同算法的實(shí)現(xiàn)蔫巩,新增或者刪除算法谆棱,對(duì)各種算法做封裝。因此圆仔,策略模式多用在算法決策系統(tǒng)中垃瞧,外部用戶只需要決定用哪個(gè)算法即可。
1. public interface ICalculator {
2. public int calculate(String exp);
3. }
4. ---------------------------------------------------------
5. public class Minus extends AbstractCalculator implements ICalculator {
6.
7. @Override
8. public int calculate(String exp) {
9. int arrayInt[] = split(exp, "-");
10. return arrayInt[0] - arrayInt[1];
11. }
12. }
13. ---------------------------------------------------------
14. public class Plus extends AbstractCalculator implements ICalculator {
15.
16. @Override
17. public int calculate(String exp) {
18. int arrayInt[] = split(exp, "\\+");
19. return arrayInt[0] + arrayInt[1];
20. }
21. }
22. --------------------------------------------------------
23. public class AbstractCalculator {
24. public int[] split(String exp, String opt) {
25. String array[] = exp.split(opt);
26. int arrayInt[] = new int[2];
27. arrayInt[0] = Integer.parseInt(array[0]);
28. arrayInt[1] = Integer.parseInt(array[1]);
29. return arrayInt;
30. }
31. }
1. public class StrategyTest {
2. public static void main(String[] args) {
3. String exp = "2+8";
4. ICalculator cal = new Plus();
5. int result = cal.calculate(exp);
6. System.out.println(result);
7. }
8. }
8. 觀察者模式(Observer)
觀察者模式很好理解坪郭,類似于郵件訂閱和 RSS 訂閱个从,當(dāng)我們?yōu)g覽一些博客或 wiki 時(shí),經(jīng)常會(huì)看到 RSS 圖標(biāo)歪沃,就這的意思是嗦锐,當(dāng)你訂閱了該文章,如果后續(xù)有更新沪曙,會(huì)及時(shí)通知你奕污。其實(shí),簡(jiǎn)單來(lái)講就一句話:當(dāng)一個(gè)對(duì)象變化時(shí)珊蟀,其它依賴該對(duì)象的對(duì)象都會(huì)收到通知菊值,并且隨著變化!對(duì)象之間是一種一對(duì)多的關(guān)系育灸。
1. public interface Observer {
2. public void update();
3. }
4.
5. public class Observer1 implements Observer {
6. @Override
7. public void update() {
8. System.out.println("observer1 has received!");
9. }
10. }
11.
12. public class Observer2 implements Observer {
13. @Override
14. public void update() {
15. System.out.println("observer2 has received!");
16. }
17. }
18.
19. public interface Subject {
20. /*增加觀察者*/
21. public void add(Observer observer);
22.
23. /*刪除觀察者*/
24. public void del(Observer observer);
25. /*通知所有的觀察者*/
1. public void notifyObservers();
2.
3. /*自身的操作*/
4. public void operation();
5. }
6.
7. public abstract class AbstractSubject implements Subject {
8.
9. private Vector<Observer> vector = new Vector<Observer>();
10.
11. @Override
12. public void add(Observer observer) {
13. vector.add(observer);
14. }
15.
16. @Override
17. public void del(Observer observer) {
18. vector.remove(observer);
19. }
20.
21. @Override
22. public void notifyObservers() {
23. Enumeration<Observer> enumo = vector.elements();
24. while (enumo.hasMoreElements()) {
25. enumo.nextElement().update();
26. }
27. }
28. }
29.
30. public class MySubject extends AbstractSubject {
31.
32. @Override
33. public void operation() {
34. System.out.println("update self!");
35. notifyObservers();
36. }
37. }
38.
39. public class ObserverTest {
40. public static void main(String[] args) {
41. Subject sub = new MySubject();
42. sub.add(new Observer1());
43. sub.add(new Observer2());
44. sub.operation();
45. }
46. }