设计模式之工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)
简单工厂模式:
角色: 抽象产品类 具体产品类 产品工厂类
定义:将被使用方的创建过程封装到一个类中,这样就在使用方和被使用方之间做了一个缓冲,也就是使用方和被使用方做了一个解耦,提高了软件的可扩展性和可维护性和可复用性.
现在有一个手机抽象类
public abstract class Phone { public abstract void makePhone(); }
两个实现类
public class XiaoMi extends Phone { @Override public void makePhone() { System.out.println("制造出了小米手机"); } }
public class HWPhone extends Phone { @Override public void makePhone() { System.out.println("制造出了华为手机"); } }
为了不让调用方直接去调用这两个类去创建实例.我们提供一个工厂类的静态方法去创建不同品牌手机的实例对象
public class PhoneFactory { public static Phone createPhone(Integer type){ Phone phone=null; if(1==type){ phone = new XiaoMi(); }else if(type==2){ phone = new HWPhone(); } return phone; } }
接下来一个客户端调用工厂类来创建
public class Consumer { public static void main(String[] args) { PhoneFactory.createPhone(1).makePhone(); PhoneFactory.createPhone(2).makePhone(); } }
输出结果:
这样我们就在使用和被使用方之间做了一层缓冲,避免了使用方和被使用方耦合性过高.当我们需要再次创建一个新品牌的手机,我们还是需要在工厂类修改代码.
所以简单工厂的使用场景:
具体类十分确定且固定的一类产品的创建,这样不至于频繁的修改工厂类的代码去实现扩展.而为了弥补简单工厂模式的缺点,再次基础上我们就要延伸下面的模式\
工厂方法模式:
角色:抽象产品类 具体产品类 抽象工厂类(只有一个接口方法生产产品) 具体工厂类
定义:将简单工厂的创建对象的方法写成一个抽象方法,也就是在工厂类或者接口中不知道如何创建该对象,创建具体对象交给工厂类的子类或者实现类去做.
我们首先改造之前的工厂类为抽象接口
public interface PhoneFactory { Phone createPhone(); }
我们为每一个手机品牌实现一个对应的工厂类
public class HWFactory implements PhoneFactory { @Override public Phone createPhone() { new HWPhone(); } }
public class XiaoMiFactory implements PhoneFactory { @Override public Phone createPhone() { return new XiaoMi(); } }
然后我们再次通过消费者调用
public class Consumer { public static void main(String[] args) { XiaoMiFactory xiaoMiFactory = new XiaoMiFactory(); xiaoMiFactory.createPhone().makePhone(); HWFactory hwFactory = new HWFactory(); hwFactory.createPhone().makePhone(); } }
输出结果:
我们在之前简单工厂的基础上,把工厂类页向上抽象了一层,这样我们需要什么工厂就去实现工厂抽象接口,获得不同的工厂,我们的工厂方法相比之前的静态方法工厂类
优点:让扩展变得简单,并且每个工厂创建不同的产品,符合单一职能原则
缺点:当新增加一个产品,需要创建对应的产品工厂类,一个工厂只能创建一个产品.
抽象工厂模式
角色:抽象产品类 具体产品类 抽象工厂类(多个生产产品方法,一个产品族) 具体工厂类
原有基础上,我们之前的抽象工厂接口只有一个创建产品的方法,在抽象工厂模式里面,我们的抽象工厂将有多个创建同一族产品的方法,架设现在我们有需要生产手机壳
手机壳抽象类
public abstract class PhoneShell { abstract void makePhoneShell(); }
手机壳实现类
public class XiaoMiShell extends PhoneShell { @Override void makePhoneShell() { System.out.println("小米手机壳"); } }
public class HWShell extends PhoneShell { @Override void makePhoneShell() { System.out.println("华为手机壳"); } }
现在我们把之前的抽象工厂类接口增加一个抽象方法
public interface PhoneFactory { Phone createPhone(); PhoneShell createShell(); }
抽象工厂实现类
public class XiaoMiFactory implements PhoneFactory { @Override public Phone createPhone() { return new XiaoMi(); } @Override public PhoneShell createShell() { return new XiaoMiShell(); } }
public class HWFactory implements PhoneFactory { @Override public Phone createPhone() { return new HWPhone(); } @Override public PhoneShell createShell() { return new HWShell(); } }
调用方
public class Consumer { public static void main(String[] args) { XiaoMiFactory xiaoMiFactory = new XiaoMiFactory(); xiaoMiFactory.createPhone().makePhone(); xiaoMiFactory.createShell().makePhoneShell(); HWFactory hwFactory = new HWFactory(); hwFactory.createPhone().makePhone(); hwFactory.createShell().makePhoneShell(); } }
输出结果:
抽象工厂模式相比工厂方法模式: 抽象工厂方法不再是单独的接口,而是生产一类产品的接口,可以生产多个相关联产品,接下来我们看下UML类图关系
抽象工厂模式的使用场景:
引用<<Java与模式>>的说法:
1:一个系统不应当依赖于产品类实例如何创建,组合和表达的细节,这对于所有形态的工厂模式都是重要的
2:这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品(上面这一条叫做抽象工厂的原始用意)
3:同属于一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来
4:系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现
为什么会有这样的说法,我想就应该深入到抽象工厂模式的起源的具体场景去讨论这个问题