Java设计模式四——工厂模式

240 阅读7分钟

###引言

在前面的设计模式中,我们在类的编写过程都是直接 new 一个对象,但是这是建立在你可以明确的知道可以创建哪一个对象的前提下,那么我们可以在编译阶段去直接实例化,但是有时候我们需要动态的选择实例化哪一个对象,这个时候就需要工厂模式来***创建一个对象***了,我们就可以获取一个对象而不需要去考虑对象的创建过程,将这个过程抛给工厂去管理,实现解耦。

我们以汽车为例子:

不使用工厂模式

比如现在一个人要一辆奥迪的车,不使用工厂模式,直接 new 一个对象,那你自己去造一辆奥迪出来吧。

public Audi getCar() {
		Audi audi =new Audi();
		return audi;
	}

可是奥迪有很多车型吧,你需要指定车型

public Audi getCar(String type) {
		Audi audi=null;
		if(type.equals("A3")) {
			audi =new AudiA3();
		}else if(type.equals("A4")) {
			audi=new AudiA4();
		}else if(type.equals("R8")) {
			audi=new AudiR8();
		}
		return audi;
	}

然而,每个人的时间都是宝贵的,我一个不是专门造车的人,有造车的时间我可以去做我自己专业领域更多的事,而且当有奥迪的新车型出来或者旧车型停产的时候我们就要去修改方法。那这个时候我们就可以使用工厂模式,工厂来专门造车,我只要去买就行了(钱多麻烦少,有钱真好......)。

简单工厂模式

创建一个Audi的简单工厂

public class SimpleAudiFactory {
	public Audi getCar(String type) {
		Audi audi=null;
		if(type.equals("A3")) {
			audi =new AudiA3();
		}else if(type.equals("A4")) {
			audi=new AudiA4();
		}else if(type.equals("R8")) {
			audi=new AudiR8();
		}
		return audi;
	}
}

用户想要车现在不用自己去造车了,只需要指定车型由工厂去造车。

public class AudiStore {
	SimpleAudiFactory factory=null;
	public AudiStore(SimpleAudiFactory factory) {
		this.factory=factory;
	}
	public Audi getCar(String type) {
		Audi audi=null;
		audi=this.factory.createCar(type);
		return audi;
	}
}

工厂方法模式

定义:工厂方法模式定义了一个创建对象的接口,但是由其子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。

这里要注意,这个“让子类决定“,并不是说让子类在运行的时候去决定,而是说对于创建者(下面例子中的 AudiStore 抽象类)来说并不需要知道实际创建了什么对象,创建者选择了什么子类那么实际创建的对象也就决定了,其实还是创建者的决定权。其次,通过让子类去具体实现创建对象,让创建者与实际产品实现了解耦,因为真正的耦合关系是在具体创建者和具体产品之间的耦合。

现在奥迪要走向全世界,每个国家的用户使用习惯不一样,日本的用户驾驶座椅要离刹车油门踏板近一点(你懂得...),英国用户的方向盘需要放在右边。一个工厂除了要造车还要考虑各种各样的差别,为新车型多增加生产线。怎么办?全世界开分店。每个国家的分店只需要考虑自己国家的车型就好了,但要说好你们这些店本质上还是属于我奥迪的品牌,别给别人卖个宝马了(可以从Audi超类中控制,控制子类必须时Audi车)。这样哪个国家的人想要奥迪,去自己家的奥迪专卖店就行了。

public abstract class AudiStore {
	public Audi getCar(String type) {
		Audi audi=null;
		audi=createAudi(type);
		return audi;
	}
	//所有分店自己来处理本地化奥迪车的生产,别生产卖个宝马就行
	protected abstract Audi createAudi(String type); 
}

日本奥迪店

public class JapanAudiStore extends AudiStore {
	public Audi createAudi(String type) {
		Audi audi=null;
		if(type.equals("A3")) {
			audi =new JapanAudiA3();
		}else if(type.equals("A4")) {
			audi=new JapanAudiA4();
		}else if(type.equals("R8")) {
			audi=new JapanAudiR8();
		}
		return audi;
	}
}

英国奥迪店

public class UKAudiStore extends AudiStore {
	public Audi createAudi(String type) {
		Audi audi=null;
		if(type.equals("A3")) {
			audi =new UKAudiA3();
		}else if(type.equals("A4")) {
			audi=new UKAudiA4();
		}else if(type.equals("R8")) {
			audi=new UKAudiR8();
		}
		return audi;
	}
}

现在用户买车要先声明自己是哪个国家的奥迪才会给你你那个国家的车

public class AudiGlobalStore {

	public static void main(String[] args) {
		//一个日本人要买一辆奥迪A4
		AudiStore jpStore=new JapanAudiStore();
		Audi audi1=jpStore.getCar("A4");
		
		//一个英国人要买一辆奥迪R8 
		AudiStore UkStore=new UKAudiStore();
		Audi audi2=UkStore.getCar("R8");

	}
}

获取Audi的过程是首先跟奥迪店(AudiStore类)的 getCar 获取车,getCar 会调用奥迪店的 createAudi 方法,但是这个方法是抽象的,具体的实例化一辆奥迪车出来,是通过其子类重写的 createAudi 方法实例出来的。

抽象工厂模式

定义:抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体的类。

以奥迪分店为例,奥迪为了保证全球奥迪汽车的品质,防止分店为了削减成本偷工减料,导致品牌的荣誉受损,现在为全球的奥迪汽车提供奥迪的零件,但是考虑到每个地区的差异,会提供差异化的零件,同时一些零件提供通用版本,由各地零售店组装。

每一辆奥迪简单描述为三个部分:轮胎(Tyre),车身(Body),内饰(Interior)。 首先定义一个零件工厂接口,接口定义所有实现此零件工厂的类都会创造这三个零件的方法。

public interface AudiPartsFactory
{
     public Tyre createTyre();
     public Body createBody();
     public Interior createInterior();
}

同时定义三个零件的超类,超类下会有不同地区的零件子类。定义不同地区的零件工厂

//英国奥迪零件工厂
public class UKAudiPartsFactory implements AudiPartsFactory
{
      public Type createTyre(){
          //所有的地区的Audi使用的都是通用的轮胎
          return new AudiGenericTyre();
      }
      //英国地区的奥迪使用UK定制的车身和内饰
      public Body createBody(){
          return new UKBody();
      }
      public Interior createInterior(){
          return new UKInterior();
      }
}
// 日本奥迪零件工厂
public class JapanAudiPartsFactory implements AudiPartsFactory{
      public Type createType(){
          return new AudiGenericType();
      }
      public Body createBody(){
          return new JapanBody();  
      }
      public Interior createInterior(){
          return new JapanInterior();
      }
}

之前我们为了区分不同的地区的Audi车,定义了JapanAudiA3,UKAudiA3之类的不同的类,现在有不同的零件工厂,我们可以使用不同的零件工厂来生产不同地区的不同的车,而不需要定义不同的类。

改造一下Audi超类

public abstract class Audi
{
      Tyre tyre;
      Body body;
      Interior interior;
      //由具体的零件工厂去实现具体车的组装。
      abstract void prepare();
}

改造具体的车型

public class AudiA3 extends Audi{
      AudiPartsFactory partsFactory;
      //构造函数,每次实力化具体的A3类的时候需要指定零件工厂
      public AudiA3(AudiPartsFactory partsFactory){
            this.partsFactory= partsFactory;
      }
      void prepare(){
            //等到的运行的时候,根据注入的不同的零件工厂,会生产不同的配套零件
            this.tyre= partsFactory.createTyre();
            this.body= partsFactory.createBody();
            this.interior = partsFactory.createInterior();
            
      }
}

之前我们的零售店是这样的

public class UKAudiStore extends AudiStore {
    public Audi createAudi(String type) {
        Audi audi=null;
        if(type.equals("A3")) {
            audi =new UKAudiA3();
        }else if(type.equals("A4")) {
            audi=new UKAudiA4();
        }else if(type.equals("R8")) {
            audi=new UKAudiR8();
        }
        return audi;
    }
}

现在有了不同的零件工厂后我们改造如下。

public class UKAudiStore extends AudiStore{
       public Audi createAudi(String type) {
        Audi audi=null;
        AudiPartsFactory partsFactory=new UKAudiPartsFactory();
        if(type.equals("A3")) {
            audi =new AudiA3(partsFactory);
        }else if(type.equals("A4")) {
            audi=new AudiA4(partsFactory);
        }else if(type.equals("R8")) {
            audi=new AudiR8(partsFactory);
        }
        return audi;
    } 

}

抽象工厂模式一般会定义两个家族,一个是工厂家族,一个产品家族(每个具体的工厂都能生产一个或者一组产品)。

总结 工厂模式主要是为了将具体的类的实现给抽取出来,降低我们的程序对于具体的类的依赖减小。不是依赖一个具体的类而是依赖具体类的抽象。 这里还要提一个设计模式里面的原则“依赖倒置原则”:不要让高层的去依赖底层组件,而是依赖于抽象,这里的高低层的区别在于抽象层次的高低,具体的类就属于低级的层次,而一般类的抽象超类或者接口就属于高级的层次。