|
|
|
@ -10,6 +10,7 @@ |
|
|
|
|
- 简单工厂模式 |
|
|
|
|
- 工厂方法模式 |
|
|
|
|
- 抽象工厂模式 |
|
|
|
|
4. 应用 |
|
|
|
|
|
|
|
|
|
#### 思维导图 |
|
|
|
|
|
|
|
|
@ -23,102 +24,138 @@ |
|
|
|
|
|
|
|
|
|
##### 简单工厂模式 |
|
|
|
|
|
|
|
|
|
我们写一个试图解析文件的例子。 |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//定义抽象产品类 |
|
|
|
|
public abstract class Product { |
|
|
|
|
public abstract void method(); |
|
|
|
|
public interface IFileParse { |
|
|
|
|
String parse(); |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//定义具体产品 |
|
|
|
|
public class ProductA extends Product { |
|
|
|
|
public class JsonFileParse implements IFileParse { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void method() { |
|
|
|
|
System.out.println("产品A"); |
|
|
|
|
public String parse() { |
|
|
|
|
return "Json"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
public class ProductB extends Product { |
|
|
|
|
|
|
|
|
|
public class XmlFileParse implements IFileParse { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void method() { |
|
|
|
|
System.out.println("产品B"); |
|
|
|
|
public String parse() { |
|
|
|
|
return "Xml"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//定义一个工厂用来生产产品 |
|
|
|
|
public class Factory { |
|
|
|
|
public static Product createProduct(String type) { |
|
|
|
|
switch (type) { |
|
|
|
|
case "A": |
|
|
|
|
return new ProductA(); |
|
|
|
|
case "B": |
|
|
|
|
return new ProductB(); |
|
|
|
|
default: |
|
|
|
|
return null; |
|
|
|
|
public class FileParseFactory { |
|
|
|
|
|
|
|
|
|
public IFileParse createFileParse(String name) { |
|
|
|
|
if ("xml".equals(name)) { |
|
|
|
|
return new XmlFileParse(); |
|
|
|
|
} else if ("json".equals(name)) { |
|
|
|
|
return new JsonFileParse(); |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//客户端根据传入的参数生成不同的产品 |
|
|
|
|
public class Client { |
|
|
|
|
public static void main(String[] args) { |
|
|
|
|
ProductA productA = (ProductA) Factory.createProduct("A"); |
|
|
|
|
if (productA != null) { |
|
|
|
|
productA.method(); |
|
|
|
|
} else { |
|
|
|
|
System.out.println("不存在产品A"); |
|
|
|
|
public class Resources { |
|
|
|
|
|
|
|
|
|
public String parse(String name) { |
|
|
|
|
IFileParse fileParse = new FileParseFactory().createFileParse(name); |
|
|
|
|
if (fileParse != null) { |
|
|
|
|
return fileParse.parse(); |
|
|
|
|
} |
|
|
|
|
throw new InvalidParameterException(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
这种写法很简单,但是问题也是显而易见的,每当增加新产品时就得改代码,违反了开闭原则。 |
|
|
|
|
|
|
|
|
|
##### 工厂方法模式 |
|
|
|
|
这个就是一个简单工厂方法的写法,不过呢,每次调用 createFileParse 都会创建一个新的 FileParse 类。实际上,如果 FileParse 可以复用,为了节省内存和对象创建的时间,我们可以把 FileParse 缓存起来。 |
|
|
|
|
|
|
|
|
|
将具体产品的创建延迟到具体工厂中完成,即由子类来决定应该实例化哪一个类。 |
|
|
|
|
具体写法就是: |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//定义一个抽象工厂类 |
|
|
|
|
public abstract class Factory { |
|
|
|
|
public abstract Product createProduct(); |
|
|
|
|
public class FileParseFactory { |
|
|
|
|
|
|
|
|
|
private static HashMap<String, IFileParse> hashMap = new HashMap<>(4); |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
hashMap.put("xml", new XmlFileParse()); |
|
|
|
|
hashMap.put("json", new JsonFileParse()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public IFileParse createFileParse(String name) { |
|
|
|
|
return hashMap.get(name); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
##### 工厂方法模式 |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//具体的工厂,生产不同的产品 |
|
|
|
|
public class FactoryA extends Factory { |
|
|
|
|
public class FileParseFactory { |
|
|
|
|
|
|
|
|
|
public interface IFileParseFactory { |
|
|
|
|
|
|
|
|
|
IFileParse createFileParse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class XmlFileParseFactory implements IFileParseFactory { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Product createProduct() { |
|
|
|
|
return new ProductA(); |
|
|
|
|
public IFileParse createFileParse() { |
|
|
|
|
return new XmlFileParse(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
public class FactoryB extends Factory { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class JsonFileParseFactory implements IFileParseFactory { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Product createProduct() { |
|
|
|
|
return new ProductB(); |
|
|
|
|
public IFileParse createFileParse() { |
|
|
|
|
return new JsonFileParse(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public IFileParse createFileParse(String name) { |
|
|
|
|
if (name.equals("xml")) { |
|
|
|
|
return new XmlFileParseFactory().createFileParse(); |
|
|
|
|
} else if (name.equals("json")) { |
|
|
|
|
return new JsonFileParseFactory().createFileParse(); |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
就是为每个 FileParse 在创建一个对应的 Factory,但是用到它时仅仅只是 new 创建了一个对象而已,这样写反而增加了复杂性,而且需要创建诸多的 Factory 类。在这个设计场景中,其实完全没有必要,简单工厂模式简单好用,比工厂方法更加适用。 |
|
|
|
|
|
|
|
|
|
那么时候该用工厂方法模式,而非简单工厂模式呢? |
|
|
|
|
|
|
|
|
|
当对象的创建逻辑比较复杂,而不是简单的 new 一下就可以,而是要组合其他类对象,做各种初始化操作的时候,我们推荐使用工厂方法模式,将复杂的创建逻辑拆分到多个工厂类中,让每个工厂类都不至于过于复杂。而使用简单工厂模式,将所有的创建逻辑都放到一个工厂类中,会导致这个工厂类变得很复杂。 |
|
|
|
|
|
|
|
|
|
##### 抽象工厂模式 |
|
|
|
|
|
|
|
|
|
抽象工厂模式的应用场景比较特殊,没有前两种常用,所以不作为重点,简单了解一下就行了。 |
|
|
|
|
|
|
|
|
|
#### 应用 |
|
|
|
|
|
|
|
|
|
在 Android 中,BitampFactory 用到了简单工厂模式,因为会根据的不同类型去创建 Bitmap。 |
|
|
|
|
|
|
|
|
|
```java |
|
|
|
|
//用户决定要生产哪个产品 |
|
|
|
|
public class Client { |
|
|
|
|
public static void main(String[] args) { |
|
|
|
|
Factory factory = new FactoryA(); |
|
|
|
|
ProductA productA = (ProductA) factory.createProduct(); |
|
|
|
|
productA.method(); |
|
|
|
|
public class BitmapFactory { |
|
|
|
|
|
|
|
|
|
new FactoryB().createProduct().method(); |
|
|
|
|
public static Bitmap decodeFile(String pathName, Options opts) { |
|
|
|
|
//... |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
缺点也是显而易见的,一个工厂只能生产一种产品,而且每一个产品都必须对应一个工厂,系统类成对增加,在一定程度上增加了系统的复杂度。 |
|
|
|
|
public static Bitmap decodeResource() { |
|
|
|
|
//... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
##### 抽象工厂模式 |
|
|
|
|
public static Bitmap decodeByteArray() { |
|
|
|
|
//... |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|