设计模式 - 工厂模式
一、原始创建
需求
客户端需要创建相应的商品,对商品做一些事,例如买卖商品等
创建方式
抽象商品:
public interface Product {
void sell();
}
实现商品:
public class Product1 implements Product {
@Override
public void sell() {
System.out.println("I am product1 and I sell for 1 dollar");
}
}
public class Product2 implements Product {
@Override
public void sell() {
System.out.println("I am product2 and I sell for 2 dollar");
}
}
在客户端直接创建商品:
public class RawClient {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int type = sc.nextInt();
sc.close();
Product product;
if (type == 1) {
product = new Product1();
} else if (type == 2) {
product = new Product2();
}
// take product do something other here... like product.sell();
}
}
问题
客户端往往是多个的, 如果 Product 相关需求改了
例如不只是两个, 要创建三个, 那么每一个客户端类都要加个 else if , 在上面的代码中需要加上 else if(type == 3) , 如果是要创建四个,那就要加上 else if(type == 4) 了...
问题抽象
问题的根本是创建部分的代码和调用类耦合度过高
二、简单工厂创建
创建方式
在工厂类创建
工厂创建:
public class SimProductFactory {
public Product createProduct(int type) {
if (type == 1) {
return new Product1();
} else if (type == 2) {
return new Product2();
} else {
throw new RuntimeException("None this type yet");
}
}
}
客户端使用工厂:
public class SimFacClient {
public static void main(String[] args) {
SimProductFactory factory = new SimProductFactory();
Product product = factory.createProduct(1);
// do something to porduct, like sell() ...
}
}
解决
解决在客户端类创建对象耦合度过高的问题
当要添加新的实体类时只需在工厂类修改即可, 不需要知道子类具体细节了
问题
问题 1 : 想要添加新的创建实体类, 就要修改工厂类
问题 2 : 若工厂类添加新的创建实体类越来越多, 导致工厂类代码臃肿难以维护
问题抽象
问题的根本就是简单工厂不符合开闭设计原则
PS : 这种问题是由于要创建的物品实体类过多才出现的,要是少量的实体类,简单工厂用起来没啥问题的!
三、工厂方法创建
创建方式
在工厂类创建,但这次有多个工厂, 客户端决定在哪个工厂类创建
抽象出工厂:
public abstract class Factory {
public abstract Product createProduct();
}
实现创建商品 1 的工厂:
public class Prod1Factory extends Factory {
@Override
public Product createProduct() {
return new Product1();
}
}
实现创建商品 2 的工厂:
public class Prod2Factory extends Factory {
@Override
public Product createProduct() {
return new Product2();
}
}
商品在工厂类创建,但由客户端决定在哪个工厂创建:
public class FactMethodClient {
public static void main(String[] args) {
Factory factory1 = new Prod1Factory();
Factory factory2 = new Prod2Factory();
Product product1 = factory1.createProduct();
Product product2 = factory2.createProduct();
// do something here to product1 or product2, like sell()...
}
}
解决
工厂方法之所以叫工厂方法,原因有二:
- 抽象了创建物品的工厂
- 抽象了工厂创建物品的方法
可以,看到它统一了创建物品的方法,要创建物品,创建一个该物品的工厂,实现创建物品的创建方法就好了,它解决了简单工厂的开闭原则问题,添加新的物品,添加对应的新物品的工厂类即可,原工厂不用修改
问题
无法解决产品族生成问题, 会导致工厂类代码过多
例如, 假设生产 Product1 它其实有一类具有共同特征的不同产品,是一个系列, 旗下有 Product1A、Product1B、Product1C、Product1D、Product1E、Product1F;生产的 Product2 它其实也是一个系列,旗下有 Product2A、Product2B、Product2C、Product2D...
这可能不大好理解:
例如,我们要卖水杯,有便宜的、一般贵、很贵的... 我们要卖苹果,也有便宜、一般贵、很贵的,所以抽象一下,便宜的商品是一族,一般贵的商品是一族、很贵的商品是一族
那么这个时候要给每个物品来一个工厂类么?那未免也太多了,如何解决?
问题抽象
最根本的问题就是由于产品族的出现,使得工厂方法的抽象度不够高,导致工厂类过多
PS : 这种问题是由于产品族的出现才有的,如果不出现产品族,工厂方法完全问题!
四、抽象工厂创建
针对产品族问题出现,它们都有共同特征,例如
-
游戏:有便宜、一般贵、很贵的等级
-
苹果:有便宜、一般贵、很贵的等级
游戏族和苹果族是不一样的,我们需要抽象出族与族直接共同的特征:便宜、一般贵、很贵
那么练习我们的举例与 product,这里简单地,就取前两个作为代表转换一下:
-
product - 商品
- productA - 很贵的商品
- productB - 一般贵的商品
-
product1 - 游戏
- product1A - 便宜的游戏
- product1B - 一般贵的游戏
-
product2 - 苹果
- product2A - 便宜的苹果
- product2B - 一般贵的苹果
在工厂方法中,我们要创建 product1A 、product1B 、product2A 、product2B 需要四个工厂,但实际上不管属于 A 还是 B 它们终究还是 product1 或者 product2,逻辑上来看,有这两个工厂就足够了
那么,接下来开始依次抽象与创建工厂!
创建方式
依次抽象商品族的共有特征:
public abstract class ProductA {
public abstract void sell();
public abstract void decribe();
}
public abstract class ProductB {
public abstract void sell();
public abstract void describe();
}
实现各族不同特征的商品:
族1的商品:
public class Product1A extends ProductA{
@Override
public void decribe() {
System.out.println("This is product1A");
}
@Override
public void sell() {
System.out.println("This product sell for A-type price which is 1.1 dollar");
}
}
public class Product1B extends ProductB{
@Override
public void sell() {
System.out.println("This is product1B");
}
@Override
public void describe() {
System.out.println("This product sell for B-type price which is 11 dollar");
}
}
族2 的商品:
public class Product2A extends ProductA {
@Override
public void decribe() {
System.out.println("This is product2A");
}
@Override
public void sell() {
System.out.println("This product sell for A-type price which is 1 dollar");
}
}
public class Product2B extends ProductB{
@Override
public void sell() {
System.out.println("This is product2B");
}
@Override
public void describe() {
System.out.println("This product sell for B-type price which is 10 dollar");
}
}
抽象出工厂类的共有特征:
public abstract class Factory {
public abstract ProductA createProductA();
public abstract ProductB createProductB();
}
依次实现创建各族的工厂类:
public class Prod1Factory extends Factory {
@Override
public ProductA createProductA() {
return new Product1A();
}
@Override
public ProductB createProductB() {
return new Product1B();
}
}
public class Prod2Factory extends Factory {
@Override
public ProductA createProductA() {
return new Product2A();
}
@Override
public ProductB createProductB() {
return new Product2B();
}
}
在客户端创建各族的商品:
public class AbstactFacClient {
public static void main(String[] args) {
Prod1Factory factory1 = new Prod1Factory();
Prod2Factory factory2 = new Prod2Factory();
ProductA product1a = factory1.createProductA();
ProductB product1b = factory1.createProductB();
ProductA product2a = factory2.createProductA();
ProductB product2b = factory2.createProductB();
// do something here to product1a product1b product2a product2b ...
}
}
解决
解决了由于产品族的出现,使得创建同一族的产品,但因为特征不同就要多设立一个工厂类导致工厂类过多的问题,抽象工厂使得每一族代表的一类产品,一族的许多产品对应一个工厂,大大减少了工厂类数量
问题
问题就是当产品族问题不存在,硬要使用抽象工厂,会显得代码更多,没有必要
问题抽象
说到底,抽象工厂是只适用于产品族问题的情况的,没用这个问题就不要用
五、总结
数量关系
通俗地说(写了好多,还是画图吧!)
-
简单工厂
商品 - 工厂 :多对一
-
工厂方法
商品 - 工厂 :一对一
-
抽象工厂
商品族 - 工厂 :一对一
适用场景
- 简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
- 工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)
- 抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)
学习有感
感觉,简单工厂,工厂方法好理解点,就是名字有点奇怪,而抽象工厂... 无非就是名字更奇怪了,这个设计模式在使用的时候,大量用到了抽象和多态上转型,所以早期学习由于这两个理解地不好,导致设计模式总是学不懂,原因在此!
在这总结一下抽象的视图... 想一下(emm,还是写了很多,还是画图吧)
-
简单工厂的应用,至少需要对产品做抽象
- Product : product 的共有信息,像可以显示描述 describe() 和卖掉 sell()
-
工厂方法的应用,需要对工厂和产品做抽象
-
Product : product 的共有信息,像可以显示描述 describe() 和卖掉 sell()
-
Factory:factory 的共有信息,像可以创建产品 createProduct()
-
PS : 多态的强大体现于此,因为 Factory 创建的时候返回类型是 Product,子类 factory 返回类型对应的是具体的 product
-
-
抽象工厂的应用,需要对产品族和工厂做抽象
- ProductA :product 族 1 2 3 的共有特征 A 的抽象
- ProductB:product 族 1 2 3 的共有特征 B 的抽象
- Factory:product 族 1 2 3 的 factory 的创建抽象,可以创建 ProductA 和 ProductB 的对象
从中,不禁感叹,能够熟练地运用抽象,是一种很强的能力,像抽象工厂,使用抽象,本来要创建六个的工厂,先在只需创建 3 个了,直接减少了一半;但对于族 1 2 3 这三个族,工厂数量再少也不能少于 3 ,因为一个族至得一个工厂,两个族使用同一个工厂,那跟简单工厂不就一样了?!