女娲造人的故事
相信这个故事大家都知道,简单来说就是女娲可以捏出不同样式的人。那么我们以这个故事为例,看看它是如何应用工厂模式的。
女娲可以类比为一个场景类Client,捏出来的人可以理解为场景类中要获得的对象。那么如何获得对象呢?很简单,捏一个不就行了嘛!那么对应到代码中就是在Client中new了一个对象出来。但是这样会出现一个问题,如果女娲要捏一种类型的人还好,但是如果类型越来越多,比如现在有黑人、白人、黄人,那么不可避免的操作就会越来越繁琐,Client中的代码也会越来越冗余。女娲希望的是直接获取到对象,而省去中间那些繁杂的初始化过程。这时候就需要一个工具来帮助女娲了,八卦炉(工厂)。现在女娲想捏出哪种类型的人,只需要把泥巴丢进八卦炉里,然后八卦炉就会塑造出对应类型的人。这样,一个简单工厂就实现了。
一、简单工厂
1.类图
2.解释
- Human接口中包含了“人”的共同属性,皮肤颜色和语言,不同种类的人对接口进行不同实现即可。
public interface Human {
//每个人种的皮肤都有相应的颜色
public void getColor();
//人类会说话
public void talk();
}
- HumanFactory是创建工厂,当要获取不同人种的对象时,只需要把不同人种作为参数传给**createHuman()**方法即可。
public class HumanFactory {
public static <T extends Human> T createHuman(Class<T> c){
//定义一个生产出的人种
Human human=null;
try {
//产生一个人种
human = (Human)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
System.out.println("人种生成错误!");
}
return (T)human;
}
}
- createHuman()方法内部对传进来的参数进行判断,从而决定如何创建对象。
public class HumanFactory {
public <T extends Human> T createHuman(Class<T> c){
//定义一个生产的人种
Human human=null;
try {
//产生一个人种
human = (T)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
System.out.println("人种生成错误!");
}
return (T)human;
}
}
3.通用实现
- 通用类图
- 抽象产品类Product
public interface Product {
}
- 具体产品类ConcreteProduct
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
- 场景类Client
public class Client {
public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
Product product = simpleFactory.createProduct(1);
// do something with the product
}
}
- 工厂类SimpleFactory
public class SimpleFactory {
public Product createProduct(int type) {
if (type == 1) {
return new ConcreteProduct1();
} else if (type == 2) {
return new ConcreteProduct2();
}
return new ConcreteProduct();
}
}
但是在简单工厂中存在一个问题,当我们的对象类型,也就是人种类型增加时,我们就需要修改HumanFactory(工厂)中的逻辑代码,这就违反了开闭原则(只进行扩展,不进行修改)。为了解决这个问题,在简单工厂的基础上提出了工厂方法模式。
二、工厂方法
1.类图
工厂方法就是在工厂的基础上加了一层抽象。用一个抽象类抽象出共同的创建对象的方法,具体的操作交给每一个工厂去执行。例如要增加一个Green Human类型人种,那么只需要创建一个GreenFactory类去继承AbstractHumanFactory类,然后实现其中的**createHuman()**抽象方法即可。这样就避免了修改而提高了扩展性。
2.解释
- AbstractHumanFactory
public abstract class AbstractHumanFactory {
//通过定义泛型对createHuman的输入参数产生两层限制:
//● 必须是Class类型;
//● 必须是Human的实现类。
public abstract <T extends Human> T createHuman(Class<T> c);
}
3.通用实现
-
定义:定义一个用于创建对象的 接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。何为实例化延迟?一个对象被消费完毕后,并不立刻释放,工厂类 保持其初始状态,等待再次被使用,这样可以限制某一个产品类的最大实例化数量。
-
通用类图
- 抽象产品类Product
public abstract class Product {
//产品类的公共方法
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}
- 具体产品类ConcreteProduct
public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
}
}
public class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
}
}
- 抽象工厂类Creater
public abstract class Creator {
/*
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String、Enum、Class等,当然也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
- 具体工厂类ConcreteCreator
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}
- 场景类Client
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}
}
既然是人,那肯定就应该分男女啊,并且应该同时出现(注意)。但是我们上述的操作并不能创建出男性人种和女性人种,那如何进行修改呢?可以用到抽象工厂模式。
三、抽象工厂
1.类图
对比一下看看有哪些改变:
-
不同的人种类型(对象类型)抽象为了一个个的抽象类,然后再创建该人种类型的男性类和女性类去继承该人种类型的抽象类。抽象类中是没有实现性别这个方法的,它交给具体的男性类和女性类去实现。
-
原本的抽象工厂类变成了工厂接口,接口中包含创建不同**人种类型(对象类型)**的方法,创建女性工厂类和男性工厂类实现该接口。(注意:对一个人种类型(对象类型)进行实例化时,女性工厂类和男性工厂类一定是同时实例化的,不过我们可以调整让他们创建出对象的比例不同,例如创建1个女性对象就要创建1.5个男性对象。)
2.解释
- 人种接口Human
public interface Human {
//每个人种都有相应的颜色
public void getColor();
//人类会说话
public void talk();
//每个人都有性别
public void getSex();
}
- 抽象人种类AbstractHuman
public abstract class AbstractWhiteHuman implements Human {
//白色人种的皮肤颜色是白色的
public void getColor(){
System.out.println("白色人种的皮肤颜色是白色的!");
}
//白色人种讲话
public void talk() {
System.out.println("白色人种会说话。");
}
}
- 具体人种性别实现类Female/Male Human
public class FemaleWhiteHuman extends AbstractWhiteHuman {
//白人女性
public void getSex() {
System.out.println("白人女性");
}
}
- 工厂接口 HumanFactory
public interface HumanFactory {
//制造一个黄色人种
public Human createYellowHuman();
//制造一个白色人种
public Human createWhiteHuman();
//制造一个黑色人种
public Human createBlackHuman();
}
- 具体性别工厂实现类Female/Male Factory
public class FemaleFactory implements HumanFactory {
//生产出黑人女性
public Human createBlackHuman() {
return new FemaleBlackHuman();
}
//生产出白人女性
public Human createWhiteHuman() {
return new FemaleWhiteHuman();
}
//生产出黄人女性
public Human createYellowHuman() {
return new FemaleYellowHuman();
}
}
3.通用实现
-
定义:抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来(男性和女性)。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
-
通用类图:
- 抽象产品类 AbstractProductA
public abstract class AbstractProductA {
//每个产品共有的方法
public void shareMethod(){
}
//每个产品相同方法,不同实现
public abstract void doSomething();
}
- 具体产品实现类ProductA1
public class ProductA1 extends AbstractProductA {
public void doSomething() {
System.out.println("产品A1的实现方法");
}
}
- 抽象工厂类AbstractCreator
public abstract class AbstractCreator {
//创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
}
- 具体工厂实现类Creator
public class Creator1 extends AbstractCreator {
//只生产产品等级为1的A产品
public AbstractProductA createProductA() {
return new ProductA1();
}
//只生产产品等级为1的B产品
public AbstractProductB createProductB() {
return new ProductB1();
}
}