女娲造人引发思考之Java设计模式:工厂模式
工厂模式的几种形态
工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态的决定将哪一个类实例化,不必事先知道每次要实例化哪一个类,工厂模式有以下几种形态:
- 简单工厂(Simple Factory)模式:又称为静态工厂方法模式
- 工厂方法(Factory Method)模式:又称为多态性工厂模式
- 抽象工厂(Abstract Factory)模式:又称为工具箱模式
简单工厂模式
示例
有一个农场,专门向外出售各种水果,现在需要下面几种水果:苹果、葡萄、草莓
定义一个水果接口,所有的水果都必须实现:
public interface Fruit {
/** 生长 */
void grow();
/** 收获 */
void harvest();
/** 种植 */
void plant();
}
苹果类:
public class Apple implements Fruit {
/** 苹果树的年龄 */
private int treeAge;
@Override
public void grow() {
System.out.println("苹果正在生长。。。");
}
@Override
public void harvest() {
System.out.println("苹果已经收获了!");
}
@Override
public void plant() {
System.out.println("苹果已经种植了!");
}
/** 辅助方法 */
public static void log(String msg) {
System.out.println(msg);
}
/** 苹果树年龄的取值方法 */
public int getTreeAge() {
return treeAge;
}
/** 苹果树年龄的赋值方法 */
public void setTreeAge(int treeAge) {
this.treeAge = treeAge;
}
}
葡萄类:
public class Grape implements Fruit {
/** 有无籽 */
private boolean seedless;
@Override
public void grow() {
System.out.println("葡萄正在生长。。。");
}
@Override
public void harvest() {
System.out.println("葡萄已经收获了!");
}
@Override
public void plant() {
System.out.println("葡萄已经种植了!");
}
/** 辅助方法 */
public static void log(String msg) {
System.out.println(msg);
}
/** 有无籽的取值方法 */
public boolean isSeedless() {
return seedless;
}
/** 有无籽的赋值方法 */
public void setSeedless(boolean seedless) {
this.seedless = seedless;
}
}
草莓类:
public class Strawberry implements Fruit {
@Override
public void grow() {
System.out.println("草莓正在生长。。。");
}
@Override
public void harvest() {
System.out.println("草莓已经收获了!");
}
@Override
public void plant() {
System.out.println("草莓已经种植了!");
}
/** 辅助方法 */
public static void log(String msg) {
System.out.println(msg);
}
}
还有一个园丁,负责水果的各种情况:
public class Farm {
public static Fruit factory(String which) {
if (which.equalsIgnoreCase("apple")) {
Apple apple = new Apple();
apple.plant();
return apple;
} else if (which.equalsIgnoreCase("grape")) {
Grape grape = new Grape();
grape.plant();
return grape;
} else if (which.equalsIgnoreCase("strawberry")) {
Strawberry strawberry = new Strawberry();
strawberry.plant();
return strawberry;
} else {
System.out.println("没有该水果!");
return null;
}
}
}
测试类:
public class Client {
public static void main(String[] args) {
Farm.factory("apple");
Farm.factory("grape");
Farm.factory("strawberry");
}
}
结构
涉及的角色:
- 工厂类(Creator)角色:担任这个角色的是工厂方法模式的核心,含有与应用密切相关的商业逻辑,工厂类在客户端的直接调用下创建产品对象,由一个Java具体类实现
- 抽象产品(Product)角色:担任这个角色的类是由工厂方法模式所创建的对象的父类,或者说它们共同拥有的接口
- 具体产品(ConcreteProduct)角色:工厂方法模式所创建的任何对象都是这个角色的实例
源代码如下:
public class Creator {
/** 静态工厂方法 */
public static Product factory() {
return new ConcreteProduct();
}
}
public interface Product {
}
public class ConcreteProduct implements Product {
}
优缺点
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
- 屏蔽产品的具体实现,调用者只关心产品的接口
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖
女娲抟土造人
在这个造人的过程中,有几个重要的角色:
- 女娲是一个工厂类,也就是简单工厂模式中的核心
- 抽象的人,就是女娲的一个想法,女娲按照这个想法,造出的一个个具体的人,便都复合这个抽象的人的定义
- 具体的人,比如张三、李四等,都是简单工厂里面的具体产品角色
工厂类角色:女娲,负责造人:
public class NuwaFactory {
public static People people(String name) {
if (name.equalsIgnoreCase("zhangSan")) {
System.out.println("女娲造人,出来个张三");
return new ZhangSan();
} else if (name.equalsIgnoreCase("lisi")) {
System.out.println("女娲造人,出来个李四");
return new LiSi();
} else {
return null;
}
}
}
抽象的人,具备吃饭、睡觉、说话等功能:
public interface People {
/** 吃饭 */
void eat();
/** 睡觉 */
void sleep();
/** 说话 */
void speak();
}
具体的人,张三、李四:
public class ZhangSan implements People {
@Override
public void eat() {
System.out.println("张三在吃饭");
}
@Override
public void sleep() {
System.out.println("张三在睡觉");
}
@Override
public void speak() {
System.out.println("张三在说话");
}
}
public class LiSi implements People {
@Override
public void eat() {
System.out.println("李四在吃饭");
}
@Override
public void sleep() {
System.out.println("李四在睡觉");
}
@Override
public void speak() {
System.out.println("李四在说话");
}
}
测试类:
public class Client {
public static void main(String[] args) {
NuwaFactory.people("zhangSan");
NuwaFactory.people("lisi");
}
}
工厂方法模式
工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中
进一步抽象化的结果,使得可以在不修改具体工厂角色的情况下引进新的产品
结构
涉及的角色:
- 抽象工厂(Creator)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口
- 具体工厂(ConcreteCreator)角色:担任这个角色的是实现了抽象工厂接口的具体Java类,具体工厂角色含有和应用密切相关的逻辑,并且受到应用程序的调用来创建产品对象
- 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,产品对象共同的父类,或者说共同拥有的接口
- 具体产品(ConcreteProduct)角色:这个角色实现了抽象产品角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品角色的实例
源码如下:
public interface Creator {
/** 工厂方法 */
Product factory();
}
public class ConcreteCreator1 implements Creator {
@Override
public Product factory() {
return new ConcreteProduct1();
}
}
public class ConcreteCreator2 implements Creator {
@Override
public Product factory() {
return new ConcreteProduct2();
}
}
public interface Product {
}
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
女娲举绳造人
在上面女娲是使用了简单工厂模式造人,然后,女娲发现她不能用这种方法造出所有的人,于是她就想出了一个聪明的办法,使用一根绳子,在泥水里搅,然后一甩,所有的泥点都变成了人
抽象工厂,仅仅声明了举绳造人的方法:
public interface NuwaFactory {
/** 举绳造人 */
People ropeMadePeople();
}
具体工厂,阳绳和阴绳:
public class Man implements NuwaFactory {
@Override
public People ropeMadePeople() {
System.out.println("阳绳造人");
return new ZhangSan();
}
}
public class Woman implements NuwaFactory {
@Override
public People ropeMadePeople() {
System.out.println("阴绳造人");
return new XiaoHong();
}
}
抽象产品,声明人的一些行为:
public interface People {
/** 吃饭 */
void eat();
/** 睡觉 */
void sleep();
/** 说话 */
void speak();
}
具体产品角色,张三、小红:
public class ZhangSan implements People {
@Override
public void eat() {
System.out.println("张三在吃饭");
}
@Override
public void sleep() {
System.out.println("张三在睡觉");
}
@Override
public void speak() {
System.out.println("张三在说话");
}
}
public class XiaoHong implements People {
@Override
public void eat() {
System.out.println("小红在吃饭");
}
@Override
public void sleep() {
System.out.println("小红在睡觉");
}
@Override
public void speak() {
System.out.println("小红在说话");
}
}
测试类:
public class Client {
public static void main(String[] args) {
NuwaFactory man = new Man();
NuwaFactory woman = new Woman();
man.ropeMadePeople();
woman.ropeMadePeople();
}
}
抽象工厂模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态
结构
涉及的角色:
- 抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,所有的具体工厂类必须实现这个Java接口或者继承这个抽象的Java类
- 具体工厂类(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例,这个角色含有选择合适的产品对象的逻辑
- 抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口
- 具体产品(Concrete Product)角色:抽象工厂模式所创建的每一个对象都是某个具体产品角色的实例
源码如下:
public interface Creator {
/** 产品A的工厂方法 */
ProductA factoryA();
/** 产品B的工厂方法 */
ProductB factoryB();
}
public class ConcreteCreator1 implements Creator {
@Override
public ProductA factoryA() {
return new ProductA1();
}
@Override
public ProductB factoryB() {
return new ProductB1();
}
}
public class ConcreteCreator2 implements Creator {
@Override
public ProductA factoryA() {
return new ProductA2();
}
@Override
public ProductB factoryB() {
return new ProductB2();
}
}
public interface ProductA {
}
public class ProductA1 implements ProductA {
}
public class ProductA2 implements ProductA {
}
public interface ProductB {
}
public class ProductB1 implements ProductB {
}
public class ProductB2 implements ProductB {
}
女娲造万物
女娲不仅仅造了人,还造了动物
女娲造万物用了抽象工厂模式,在这个故事里面,女娲的产品有两个划分方法,一个是按照产品是人还是动物来划分,一个是按照产品是男女、雌雄来划分
- 神绳接口作为抽象工厂角色
- 人接口作为人类抽象角色,动物接口作为动物类抽象角色
- 阴绳、阳绳继承自神绳接口,是具体的绳子类
- 亚当、夏娃是具体的人类,公牛、母马是具体的动物类
抽象工厂:
public interface NuwaGodRope {
/** 神绳造人 */
People ropeMadePeople();
/** 神绳造动物 */
Animal ropeMadeAnimal();
}
具体工厂角色:
public class YangRope implements NuwaGodRope {
@Override
public People ropeMadePeople() {
System.out.println("女娲造出亚当");
return new Adam();
}
@Override
public Animal ropeMadeAnimal() {
System.out.println("女娲造出公牛");
return new TheBull();
}
}
public class YinRope implements NuwaGodRope {
@Override
public People ropeMadePeople() {
System.out.println("女娲造出夏娃");
return new Eve();
}
@Override
public Animal ropeMadeAnimal() {
System.out.println("女娲造出母马");
return new Mare();
}
}
人类接口:
public interface People {
/** 吃饭 */
void eat();
/** 睡觉 */
void sleep();
/** 说话 */
void speak();
}
具体的产品,即具体的某个人:
public class Adam implements People {
@Override
public void eat() {
System.out.println("亚当在吃饭");
}
@Override
public void sleep() {
System.out.println("亚当在睡觉");
}
@Override
public void speak() {
System.out.println("亚当在说话");
}
}
public class Eve implements People {
@Override
public void eat() {
System.out.println("夏娃在吃饭");
}
@Override
public void sleep() {
System.out.println("夏娃在睡觉");
}
@Override
public void speak() {
System.out.println("夏娃在说话");
}
}
动物类接口:
public interface Animal {
/** 吃饭 */
void eat();
/** 睡觉 */
void sleep();
/** 叫唤 */
void call();
}
具体的某个动物:
public class TheBull implements Animal {
@Override
public void eat() {
System.out.println("公牛在觅食");
}
@Override
public void sleep() {
System.out.println("公牛在睡觉");
}
@Override
public void call() {
System.out.println("公牛在叫唤");
}
}
public class Mare implements Animal {
@Override
public void eat() {
System.out.println("母马在觅食");
}
@Override
public void sleep() {
System.out.println("母马在睡觉");
}
@Override
public void call() {
System.out.println("母马在叫唤");
}
}
测试类:
public class Client {
public static void main(String[] args) {
NuwaGodRope yangRope = new YangRope();
NuwaGodRope yinRope = new YinRope();
People adam = yangRope.ropeMadePeople();
adam.sleep();
System.out.println();
Animal theBull = yangRope.ropeMadeAnimal();
theBull.call();
System.out.println();
People eve = yinRope.ropeMadePeople();
eve.eat();
System.out.println();
Animal mare = yinRope.ropeMadeAnimal();
mare.sleep();
}
}