工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类。
目录
一、工厂模式的形态
二、简单工厂(Simple Factory)
三、工厂方法(Factory Method)(优点在于横向扩展)
四、抽象工厂(Factory Method)
五、适用场景:
工厂模式主要有以下几种形态:
定义:专门定义一个类(第三方)来创建其他类实例(解耦,将客户端创建对象的操作解耦到外部第三方类),被创建的实例通常都具有共同的父类。 --用于没有产品族并且产品个数较少
eg:
首先定义一个抽象类:机器,可以用来生产电脑
然后定义多个具体产品类:产品流水线,每个流水线负责生产该品牌产品
最后定义一个工厂类:工厂类中有许多不同流水线,其中可以生产多品牌电脑
用户想要的时候,只用在客户端输入想要的产品,与此对应的产品就会从工厂中生产,用户不必知道是如何生产的
组成: a.一个抽象类 interface factory
b.N个具体产品类 class MacBook implements factory{} class Aline implements factory{} ......
c.一个工厂类 class RealFactory{ public static factory produce(String pro){...} }
//简单工厂模式
//定义一个抽象类,假设这是一个生产电脑的机器
interface factory{
void create();
}
//---------------------- 多个具体产品类 -------------------------------------
//定义一个产品类,使用此机器生产品牌电脑
class MacBook implements factory{
@Override
public void create() {
System.out.println("生产一个MacBook电脑");
}
}
class Acer implements factory{
@Override
public void create() {
System.out.println("生产一个Acer电脑");
}
}
class Aline implements factory{
@Override
public void create() {
System.out.println("生产一个Aline电脑");
}
}
//---------------------------------------------------------------
//定义一个工厂类,拥有几条流水线工程来生产不同品牌的电脑
class RealFactory{
public static factory produce(String name) {
if (name.equals("MacBook")) {
return new MacBook();
} else if (name.equals("Acer")) {
return new Acer();
} else if (name.equals("Aline")) {
return new Aline();
}
System.out.println("此工厂不生产"+name);
return null;
}
}
public class SimpleFactory {
public static void main(String[] args) {
RealFactory fac = new RealFactory();
System.out.println("请输入你想要的电脑:");
Scanner in = new Scanner(System.in);
String name = in.next();
fac.produce(name).create();
}
}
结果:
由上面的代码可以看出,简单工厂的核心就是一个RealFactory类,他拥有必要的逻辑判断能力和所有产品的创建权利,我们只需要向把定单给他,就能得到我们想要的产品。这使用起来似乎非常方便。
但是,实际上,这个RealFactory有很多的局限。首先,我们每次想要增加一种新产品的时候,都必须修改RealFactory的原代码,这显然违反了开闭原则。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,其代码量也将不断地激增,这非常不符合我们的编码原则。还有就是,整个系统都严重依赖RealFactory类,如果RealFactory类出问题,系统就进入不能工作的状态,这也是最为致命的一点....
所以简单工厂只适合于产品对象较少,且产品固定的需求,对于产品变化无常的需求来说显然不合适
以上的不足将在工厂模式的另外两种状态中得到解决。
上面的代码告诉我们,简单工厂是整个模式的核心,一旦他出了问题,整个模式都将受影响而不能工作,为了降低风险和为日后的维护、扩展做准备,我们需要对它进行重构,引入工厂方法。
定义:工厂方法定义一个用来创建对象的接口,用多态来削弱了工厂类的职能,让子类决定实例化哪一个工厂。
eg:
首先定义一个抽象类:机器,可以用来生产电脑
然后定义多个具体产品类:产品流水线,每个流水线负责生产该品牌产品
然后定义一个抽象工厂,工厂可以流水线生产电脑
最后定义多个工厂类:每个工厂可以生产自己品牌的电脑
用户想要的时候,只用找到对应品牌的工厂发送请求,与此对应的产品就会从工厂中生产,每个品牌工厂自己管理自己流水线电脑,其他的工厂产品出问题或者倒闭了都和自家的没关系:)
组成: a. 一个抽象产品类 interface Computre
b.多个具体产品类 class MacBook implements Computre 。。。
c.一个抽象工厂 interface ComputerFactory
d.多个具体工厂(每个产品族对应一个具体工厂) class msFactory implements ComputerFactory
interface Computre{
void create();
}
//---------------------- 多个具体产品类 -------------------------------------
class MacBook implements Computre{
@Override
public void create() { System.out.println("生产一个MacBook电脑"); }
}
class Aline implements Computre{
@Override
public void create() {System.out.println("生产一个外星人电脑");}
}
class Acer implements Computre{
@Override
public void create() {System.out.println("生产一个Acer电脑"); }
}
//------------------------------------------------------------------------------
interface ComputerFactory{
Computre createComputer();
}
//---------------------- 多个具体工厂 -------------------------------------
//弘基电脑工厂
class msFactory implements ComputerFactory{
@Override
public Computre createComputer() {
return new Acer();
}
}
//苹果产品工厂
class AppleFactory implements ComputerFactory{
@Override
public Computre createComputer() {
return new MacBook();
}
}
//微软产品工厂
class AcerFactory implements ComputerFactory{
@Override
public Computre createComputer() {
return new Aline();
}
}
//------------------------------------------------------------------------------
public class FactoryMethod{
public static void main(String[] args) throws InterruptedException {
ComputerFactory computerFactory = new AppleFactory();
Computre computre = computerFactory.createComputer();
computre.create();
}
}
从上面创建产品的栗子可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品放在实现了工厂接口的不同工厂类里面,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,就能达到,不用修改已有的代码。
但是工厂方法也有他局限的地方,那就是当面对的产品有复杂的等级结构的时候,例如,苹果工厂除了生产电脑,还生产手机产品,这样一来电脑和手机就是两大产品家族了,这两大家族下面包含了数量众多的产品,每个产品又会有多个型号,这样就形成了一个复杂的产品树了。如果用工厂方法来设计这个产品家族系统,就必须为每个型号的产品创建一个对应的工厂类,当有数百种甚至上千种产品的时候,也必须要有对应的上百成千个工厂类,这在现实中显然是不可能发生的。
抽象工厂:意的意图在于创建一系列互相关联或互相依赖的对象。
特点:提供一个创建一系列相关或相互依赖对象的接口(抽象工厂、多条产品线),而无需指定他们具体的类。
抽象工厂和工厂方法的模式基本一样,区别在于,工厂方法是生产一个具体的产品,而抽象工厂可以用来生产一组相同,有相对关系的产品;重点在于一组,一批,一系列。
举个例子,假如生产华为手机,小米手机有很多系列,华为荣耀系列、华为P系列、华为Nova系列等;假如Nova3生产需要的配件有麒麟970的处理器,6.3英寸屏幕,而荣耀10只需要麒麟940的处理器和5.84寸的屏幕就可以了;用抽象工厂来实现:
//抽象工厂
//CPU接口
interface Cpu {
void run();
class Cpu940 implements Cpu {
@Override
public void run() { System.out.println("我的CPU是麒麟940呦"); }
}
class Cpu970 implements Cpu {
@Override
public void run() { System.out.println("我的CPU是麒麟970"); }
}
}
//屏幕接口
interface Screen {
void size();
class Screen5 implements Screen {
@Override
public void size() { System.out.println("我的屏幕是5寸"); }
}
class Screen6 implements Screen {
@Override
public void size() { System.out.println("我的屏幕是6寸"); }
}
}
//工厂接口
interface PhoneFactory {
Cpu getCpu();//使用的cpu
Screen getScreen();//使用的屏幕
}
//--------------------------------具体实现类---------------------------
//Nova3
class Nova3Factory implements PhoneFactory {
@Override
public Cpu getCpu() { return new Cpu.Cpu970(); }
@Override
public Screen getScreen() { return new Screen.Screen6(); }
}
//荣耀10
class HonorFactory implements PhoneFactory {
@Override
public Cpu getCpu() { return new Cpu.Cpu940(); }
@Override
public Screen getScreen() { return new Screen.Screen5(); }
}
//-------------------------------------------------------------------
public class AbstFactory {
public static void main(String[] args) {
PhoneFactory phone = new Nova3Factory();
phone.getCpu().run();
phone.getScreen().size();
}
}
从以上的例子可以看出,抽象工厂可以解决一系列的产品生产的需求,对于大批量,多系列的产品,用抽象工厂可以更好的管理和扩展;
无论是简单工厂模式,工厂方法模式还是抽象工厂模式,它们都具有类似的特性,适用场景也十分类似。
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的产品,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。