什么是工厂方法模式 定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
Creator是一个类(接口),有一个工厂方法 factoryMethod()
,由子类去实现。
ConcreteCreator实现了 factoryMethod()
以实际制造出一种或多种产品。如ConcreteProduct。所有的产品实现公同的接口Product,这样生产出的产品就可以引用这个接口,而不是真正的实现类。
如何设计 假设有一个音乐播放器,可以根据用户的喜好去推送音乐。可以有中文和英文歌曲,下面又有分类:电子(Electronic),华语(Chinese),流行(Popular)等。
代码如下:
定义工厂接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package creator;import music.Music;public interface MusicCreator { int POPULAR = 1 ; int ROCK = 2 ; int ELECTRONIC = 3 ; Music createMusic (int style) ; }
具体的生产类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 package creator;import music.Music;import music.ChineseElectronicMusic;import music.ChinesePopularMusic;import music.ChineseRockMusic;public class ChineseMusicCreator implements MusicCreator { @Override public Music createMusic (int style) { Music music; switch (style) { case POPULAR: music = new ChinesePopularMusic (); break ; case ROCK: music = new ChineseRockMusic (); break ; case ELECTRONIC: music = new ChineseElectronicMusic (); break ; default : music = new ChinesePopularMusic (); } return music; } } package creator;import music.EnglishElectronicMusic;import music.EnglishPopularMusic;import music.EnglishRockMusic;import music.Music;public class EnglishMusicCreator implements MusicCreator { @Override public Music createMusic (int style) { Music music; switch (style) { case POPULAR: music = new EnglishPopularMusic (); break ; case ROCK: music = new EnglishRockMusic (); break ; case ELECTRONIC: music = new EnglishElectronicMusic (); break ; default : music = new EnglishPopularMusic (); } return music; } }
产品接口 1 2 3 4 5 6 7 8 9 10 11 12 13 package music;public interface Music { void playMusic () ; }
具体的产品 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 package music;public class ChineseElectronicMusic implements Music { @Override public void playMusic () { System.out.println("中文电子音乐~~~~" ); } } package music;public class ChinesePopularMusic implements Music { @Override public void playMusic () { System.out.println("中文流行音乐!!!" ); } } package music;public class ChineseRockMusic implements Music { @Override public void playMusic () { System.out.println("中文摇滚音乐~~~~~" ); } } package music;public class EnglishElectronicMusic implements Music { @Override public void playMusic () { System.out.println("英文电子音乐~~~~" ); } } package music;public class EnglishPopularMusic implements Music { @Override public void playMusic () { System.out.println("英文流行音乐!!!" ); } } package music;public class EnglishRockMusic implements Music { @Override public void playMusic () { System.out.println("英文摇滚音乐~~~~~" ); } }
客户端代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import creator.ChineseMusicCreator;import creator.EnglishMusicCreator;import creator.MusicCreator;import music.Music;public class Main { public static void main (String[] args) { MusicCreator englishMusicCreator = new EnglishMusicCreator (); Music englishMusic = englishMusicCreator.createMusic(MusicCreator.POPULAR); englishMusic.playMusic(); MusicCreator chineseMusicCreator = new ChineseMusicCreator (); Music chineseMusic = chineseMusicCreator.createMusic(MusicCreator.POPULAR); chineseMusic.playMusic(); } }
在简单工厂模式中,我们会把所有的产品在一个类中去判断,然后生产出要的产品。这就导致如果有新的种类产品的时候 我们就要去修改原来的工厂方法,这就违反了开-闭原则。
工厂方法模式是对简单工厂模式进一步的解耦,因为在工厂方法模式中是一个或多个子类对应一个工厂类,而这些工厂类都实现于一个抽象接口。这相当于是把原本会因为业务代码而庞大的简单工厂类,拆分成了一个个的工厂类,这样代码就不会都耦合在同一个类里了,就像把一个大蛋糕切成了多个小蛋糕。
设计原则
依赖倒置原则,即不能让高级组件依赖低级组件,而且不管高级组件或低级组件,都应该依赖抽象。
在上面的例子中MusicCreator是高级组件,具体的音乐实现类是低级组件,它们都依赖了Music这个抽象。所以遵循了依赖倒置原则。