一、认识抽象工厂模式
抽象工厂模式也是工厂模式的一种,相对于简单工厂模式、工厂方法模式考虑的是一类产品的生产,而抽象工厂模式则是考虑多个产品族的创建。在抽象工厂模式中,有一个抽象工厂,该抽象工厂中提供了产生不同抽象产品的方法。其中抽象工厂是可以创建工厂的工厂!
定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口无需指定它们具体的类。
应用场景:
提供一个产品类的工厂,所有的产品以同样的接口出现,使用者不依赖于具体的实现。
强调一些列相关的产品对象(如下面示例的产品族),一起使用创建对象需要大量重复的代码。
结构:抽象工厂、具体工厂;抽象产品、具体产品。
优缺点:
优点:获取具体系列产品只需要通过具体系列工厂获取,无序关心创建的细节;
缺点:规定了所有可能被创建的产品集合,若是出现某一个系列出现新的产品就会导致所有的系列都会创建指定的接口!扩展新产品困难,增加了系统的抽象性与复杂度。
引用 C语言中文网—抽象工厂模式图
二、实现抽象工厂模式
2.1、代码实现
在Abstract目录下的是抽象工厂模式代码:
抽象产品:Iphone、Router
//手机接口 public interface Iphone { void start(); void music(); void ring(); void stop(); } //路由器接口 public interface Router { void start(); void stop(); void work(); }
抽象工厂解决的是一个产品族的创建,品牌可以有多个,一个品牌也会生产不同的产品,其不同品牌的相同产品我们就可以将其进行抽象,由于我们注重的并不是一个产品的创建而是一个产品族,所以我们还需要抽象一个品牌接口即相当于是一个抽象工厂,该抽象工厂可以创建具体的工厂(实现其接口)。
抽象工厂:Brand
//品牌接口(可根据不同的品牌获取不同的产品) public interface Brand { Iphone getPhone(); Router getRouter(); }
具体产品:HuaWeiPhone、LianXiangPhone、HuaWeiRouter、LianXiangRouter
//手机的实现类 //华为牌手机 public class HuaWeiPhone implements Iphone { @Override public void start() { System.out.println("华为手机启动中..."); } @Override public void music() { System.out.println("华为手机播放音乐中..."); } @Override public void ring() { System.out.println("华为手机开启闹铃中..."); } @Override public void stop() { System.out.println("华为手机关机中..."); } } //联想牌手机 public class LianXiangPhone implements Iphone { @Override public void start() { System.out.println("联想手机正在启动..."); } @Override public void music() { System.out.println("联想手机播放音乐中..."); } @Override public void ring() { System.out.println("联想手机开启闹铃..."); } @Override public void stop() { System.out.println("联想手机关机中..."); } } //路由器的实现类 //华为路由器 public class HuaWeiRouter implements Router{ @Override public void start() { System.out.println("华为路由器正在启动..."); } @Override public void stop() { System.out.println("华为路由器正在关机..."); } @Override public void work() { System.out.println("华为路由器开始工作..."); } } //联想路由器 public class LianXiangRouter implements Router{ @Override public void start() { System.out.println("联想路由器正在启动..."); } @Override public void stop() { System.out.println("联想路由器正在关机..."); } @Override public void work() { System.out.println("联想路由器开始工作..."); } }
具体工厂:既然产品有了,那我们一定是从指定工厂中来获取产品,接着我们通过抽象工厂来创建工厂类:
//华为工厂(提供华为手机、华为路由器) public class HuaWeiFactory implements Brand{ @Override public Iphone getPhone() { return new HuaWeiPhone(); } @Override public Router getRouter() { return new HuaWeiRouter(); } } //联想工厂(提供联想手机、联想路由器) public class LianXiangFactory implements Brand{ @Override public Iphone getPhone() { return new LianXiangPhone(); } @Override public Router getRouter() { return new LianXiangRouter(); } }
最终我们来创建一个顾客类Customer,获取不同品牌的产品并且使用产品:
public class Customer { public static void main(String[] args) { //获取华为工厂 Brand huawei = new HuaWeiFactory(); Iphone phone = huawei.getPhone();//华为工厂获取华为手机 phone.start(); phone.music(); phone.ring(); phone.stop(); Router router = huawei.getRouter();//华为工厂获取华为路由器 router.start(); router.work(); router.stop(); //---------------------- System.out.println(); Brand lianxiang = new LianXiangFactory(); Iphone phone1 = lianxiang.getPhone();//华为工厂获取华为手机 phone1.start(); phone1.music(); phone1.ring(); phone1.stop(); Router router1 = lianxiang.getRouter();//华为工厂获取华为路由器 router1.start(); router1.work(); router1.stop(); } }
2.2、分析说明
在上面顾客类中的测试方法里,我们通过不同的工厂来获取到不同品牌的产品,具体的产品进行了代码的隔离,无需关心创建过程中的细节!
我们看下上面整体代码的依赖图:
将具体产品类型进行抽象,将具体生产商抽象成一个工厂并提供获取抽象产品的接口。
当我们需要具体的产品时只需要通过具体的工厂的方法即可获取,而不用再去管其中的细节。
若是我们要添加其他品牌如小米,我们只需要实现Brand接口创建一个工厂,分别实现其接口即可,符合开闭原则;若是新增一个产品A,那么就需要在Brand中添加获取A的接口,那么其所有实现该接口的工厂类都需要修改,这就不符合开闭原则。
总结
1、抽象工厂由四个部分组成:抽象工厂、具体工厂;抽象产品、具体产品。
2、添加新的产品族时只需要实现抽象工厂接口创建一个工厂并实现其中的方法即可,符合了开闭原则;而对于添加某个新产品则需要添加抽象工厂的接口,即造成所有抽象工厂的实现类都要进行修改,这就违反了开闭原则。
3、针对于抽象工厂模式不可以增加产品,可以增加产品族!(一旦增加产品就会造成大量修改)。
4、对于抽象工厂模式针对于的是产品族!