乐趣区

关于java:开发者必修必会的设计模式之工厂模式

本文首发自 [慕课网](imooc.com),想理解更多 IT 干货内容,程序员圈内热闻,欢送关注 ” 慕课网 ” 及“慕课网公众号”!
作者:李一鸣 | 慕课网讲师


工厂模式

工厂模式是平时开发过程中最常见的设计模式。工厂模式解决类的实例化问题,它属于创立型模式。工厂模式也常常会和其余设计模式组合应用。

试想你去麦当劳买一个汉堡。你只须要通知收银员要一个 xx 汉堡。过一会就会有一个此类型的汉堡被制作进去。而你齐全不须要晓得这个汉堡是怎么被制作进去的。这个例子中你就是客户端代码,麦当劳就是工厂,负责生产汉堡。汉堡是接口,而具体的某一种汉堡,比如说香辣鸡腿堡,就是实现了汉堡接口的类。

咱们持续通过另外一个例子,深刻了解工厂模式。当初咱们给某款音乐软件开发一个举荐性能。需要是可能依据用户抉择的音乐风格,举荐不同格调的歌曲清单。那么你打算怎么实现呢?

1. 音乐举荐器 1.0 版本

如果之前没有学习过设计模式,很可能你的实现会是这样。编写 RecommendMusicService 类,外面有一个 Recommend 办法。依据输出的格调不同,执行不同的举荐逻辑。代码如下:

public class RecommendMusicService {public List<String> recommend(String style) {List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {recommendMusicList.add("Don't cry");
        } else if ("country".equals(style)) {recommendMusicList.add("Hotel california");
        } else if ("grunge".equals(style)) {recommendMusicList.add("About a girl");
        }else {recommendMusicList.add("My heart will go on");
        }

        return recommendMusicList;
    }
}

是不是感觉 recommed 办法太长了? OK,咱们重构下,把每种音乐风格的举荐逻辑封装到相应的办法中。这样举荐办法就能够复用了。

public class RecommendMusicService {public List<String> recommend(String style) {List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {recommendMetal(recommendMusicList);
        } else if ("country".equals(style)) {recommendCountry(recommendMusicList);
        } else if ("grunge".equals(style)) {recommendGrunge(recommendMusicList);
        }else {recommendPop(recommendMusicList);
        }

        return recommendMusicList;
    }

    private void recommendPop(List<String> recommendMusicList) {recommendMusicList.add("My heart will go on");
        recommendMusicList.add("Beat it");
    }

    private void recommendGrunge(List<String> recommendMusicList) {recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");
    }

    private void recommendCountry(List<String> recommendMusicList) {recommendMusicList.add("Hotel california");
        recommendMusicList.add("Take Me Home Country Roads");
    }

    private void recommendMetal(List<String> recommendMusicList) {recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");
    }
}

这样是不是很完满了!recommend 办法精简了很多,而且每种不同的举荐逻辑都被封装到相应的办法中了。那么,如果再加一种格调举荐怎么办?这有什么难,recommed 办法中加分支就好啦。而后在 RecommendMusicService 中减少一个对应的举荐办法。
等等,是不是哪里不太对?回忆一下设计模式 6 大准则的开闭准则 —- 对扩大凋谢,对批改敞开。面对新格调举荐的需要,咱们始终都在批改 RecommendMusicService 这个类。当前每次有新格调举荐要增加,都会导致批改 RecommendMusicService。显然这是个坏滋味。

那么如何做到实现新的格调举荐需要时,满足开闭准则呢?

2. 音乐举荐器 2.0 版本

增加新需要时,如何做到不批改,去扩大?是不是想到了繁多职责?是的,类的职责越繁多,那么它就越稳固。RecommendMusicService 类的职责太多了,负责 n 种格调的举荐。OK,那么咱们第一件事就是要缩小 RecommendMusicService 类的职责,把每种不同格调的举荐提取到不同的类当中。
比方 MetalMusicRecommendServicePopMusicRecommendServiceCountryMusicRecommendService。这些类都能够通过 recommed 办法生成举荐的歌曲清单。而 RecommendMusicService 类只是通过调用不同 MusicRecommendService 的 recommed 办法来实现举荐。代码如下:
MetalMusicRecommendService 类:

public class MetalMusicRecommendService {public List<String> recommend(){List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("Don't cry");
        recommendMusicList.add("Fade to black");

        return recommendMusicList;
    }
}

同类型的还有 GrungeMusicRecommendServicePopMusicRecommendServiceCountryMusicRecommendService

当初咱们来革新 MusicRecommendService 类:

public class RecommendMusicService {private MetalMusicRecommendService metalMusicRecommendService = new MetalMusicRecommendService();
    private GrungeMusicRecommendService grungeMusicRecommendService = new GrungeMusicRecommendService();
    private CountryMusicRecommendService countryMusicRecommendService = new CountryMusicRecommendService();
    private PopMusicRecommendService popMusicRecommendService = new PopMusicRecommendService();

    public List<String> recommend(String style) {List<String> recommendMusicList = new ArrayList<>();

        if ("metal".equals(style)) {metalMusicRecommendService.recommend();
        } else if ("country".equals(style)) {countryMusicRecommendService.recommend();
        } else if ("grunge".equals(style)) {grungeMusicRecommendService.recommend();
        }else {popMusicRecommendService.recommend();
        }

        return recommendMusicList;
    }

}

革新后,如果有了新音乐风格举荐的需要,只须要减少相应的 xxxMusicRecommendService 类。而后在 RecommendMusicService 中减少相应分支即可。这样就做到了开闭准则。那么还有什么违反设计准则的中央吗?RecommendMusicService 是不是依赖的 xxMusicRecommendService 类太多了?

没错,而且这么多类,实际上都是做举荐的事件,且都是通过 recommend 办法提供举荐后果。这齐全能够形象出接口,比方 MusicRecommendInterface。那么 RecommendMusicService 依赖 MusicRecommendInterface 就能够了。这解决了依赖反转问题 —- 应该依赖接口,而不是依赖具体实现。

咱们又温习了繁多职责和依赖反转准则。不愧是领导设计模式的准则,真的是无处不在。依赖 MusicRecommendInterface 没问题,然而不同的音乐风格,怎么能实例化 MusicRecommendInterface 的某个具体实现呢?工厂模式于是就应运而生了!

3. 音乐举荐器 3.0 版本

咱们回顾一下文章结尾说到,工厂模式解决的是类的实例化。无论你须要哪种格调的 MusicRecommendService,只须要通知工厂,工厂会给你实例化好你须要的具体实现。而工厂能做到这些是基于继承和多态。
RecommendMusicService 只须要依赖 MusicRecommendInterface,具体须要哪个MusicRecommendService 的实现,只须要通知 RecommendServiceFactory 即可。MusicRecommendService 拿到具体的实现后调用它的 recommand 办法,就能够失去相应格调的举荐歌曲清单。

首先咱们须要定义所有 MusicRecommendService 要实现的接口,很简略,只有一个 recommend 办法:

public interface MusicRecommendInterface {List<String> recommend();
}

咱们 2.0 版本中的 xxxMusicRecommendService 都须要实现此接口,例如:

public class GrungeMusicRecommendService implements MusicRecommendInterface {public List<String> recommend() {List<String> recommendMusicList = new ArrayList<>();

        recommendMusicList.add("About a girl");
        recommendMusicList.add("Smells like teen spirit");

        return recommendMusicList;
    }
}

不同音乐风格的举荐逻辑在各自实现的 recommend() 办法中。
上面就是工厂模式中的工厂代码了,其实很简略,只是依据不同的参数实例化不同的实现并返回。

public class MusicRecommendServiceFactory {MusicRecommendInterface createMusicRecommend(String style) {if ("metal".equals(style)) {return new MetalMusicRecommendService();
        } else if ("country".equals(style)) {return new CountryMusicRecommendService();
        } else if ("grunge".equals(style)) {return new GrungeMusicRecommendService();
        } else {return new PopMusicRecommendService();
        }
    }
}

咱们再来看看 RecommendMusicService 的代码:

public class RecommendMusicService {private MusicRecommendServiceFactory recommendMusicServiceFactory = new MusicRecommendServiceFactory();

    public List<String> recommend(String style) {MusicRecommendInterface musicRecommend = recommendMusicServiceFactory.createMusicRecommend(style);

        return musicRecommend.recommend();}
}

是不是简略多了,曾经不再依赖那么多的 MusicRecommendInterface 的实现了。它要做的事件仅仅是通过工厂失去想要的 RecommendMusicService 实现,而后调用它的 recommend() 办法,就能够失去你想要的举荐后果。
类图如下:

以上三种实现形式总结如下:

4. 小结

咱们通过音乐举荐器的例子,实际了如何找到程序中违反设计准则的中央,并通过工厂模式来解决这些问题。应用设计模式能够让程序更合乎程序设计准则,从而写出更为强壮的代码。咱们应牢记工厂模式解决的是类的实例化问题。这个例子很简略,不过波及到的知识点却很多。有封装、多态、繁多职责和依赖反转等。可见要想把程序设计好,必须熟练掌握这些基本概念和准则。


欢送关注「慕课网」官网帐号,咱们会始终保持提供 IT 圈优质内容,分享干货常识,大家一起独特成长吧!

本文原创公布于慕课网,转载请注明出处,谢谢合作

退出移动版