设计模式--工厂模式
在最初的学习过程中对把简单的东西搞得复杂的现象很不理解,随着经验的增长,慢慢发现我所理解的“简单”其实是针对设计的简单,这种代码缺少灵活性,目的仅仅是为了解决现有问题。而“复杂”恰恰是针对一类问题的万能方案,他可以让代码变得优雅,灵活不再是一个臃肿的胖子。
在对模式的学习过程中很容易误入歧途,陷入形式主义,对模式细节的过多关注恰恰使我们越陷越深,子曾经曰过:“学而不思则罔”,文档中的类图和实现代码往往并不能代表模式的全部,我们学习模式的重点要放在模式的意图上。
设计模式代表了最佳的实践,是开发人员在开发过程中面临一般问题的解决方案,是众多前辈们在经过相当长一段时间的试验和错误中总结出来的。
什么是设计模式
设计模式:是一套被反复使用、多数人知晓、经过分类编目的代码设计经验的总结。
使用设计模式的目的
使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码的可靠性。
设计模式的分类
设计模式的分类
- 创建型模式:创建型模式涉及对象的实例化,用于解耦对象的实例化过程,不让用户代码依赖于对象的创建或排列方式,避免用户直接使用new创建对象。。
- 结构型模式:把类或对象结合在一起形成一个更大的结构,和类有关的结构型模式涉及如何合理使用继承机制;和对象有关的结构型模式涉及如何合理的使用对象组合机制。。
- 行为型模式: 行为型模式涉及怎样合理的设计对象之间的交互通信,以及怎样合理为对象分配职责,让设计富有弹性,易维护,易复用。
工厂模式
意图:定义一个创建对象的接口。让其子类决定实例化哪一个类。使其实例化过程延迟到子类进行。
工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
三个工厂
-
简单工厂模式
简单工厂模式又叫静态工厂方法模式,实际不能算作一种设计模式。
GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式与抽象工厂模式。将简单工厂模式看为工厂方法模式的一种特例,两者归为一类。
意图:定义一个用于创建对象的接口
具体实现:
抽象一个产品基类,(接口也可以)
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:产品的抽象类
*/
public abstract class Coffee {
/**
* 展示产品详情
*/
public abstract void details();
}
产品的具体实现
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description: 美式咖啡
*/
public class Americano extends Coffee {
@Override
public void details() {
System.out.print("美式咖啡,不便宜");
}
}
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:拿铁咖啡
*/
public class Latte extends Coffee {
@Override
public void details() {
System.out.print("拿铁咖啡,不便宜");
}
}
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:雀巢咖啡
*/
public class Nescafe extends Coffee {
@Override
public void details() {
System.out.print("雀巢咖啡,喝得起");
}
}
简单工厂来创建不同类型的咖啡实例
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description: 简单工厂
*/
public class SimpleFactory {
/**
* 通过传递过来的类型创建不同实例
* @param type
* @return
*/
public static Coffee createInstance(String type) {
if (type.equals("Americano")) {
return new Americano();
} else if (type.equals("Latte")) {
return new Latte();
} else if (type.equals("Nescafe")) {
return new Nescafe();
} else {
throw new RuntimeException("没有匹配到可实例化[" + type + "]对象");
}
}
}
使用
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:
*/
public class Test {
public static void main(String[] args) {
Coffee latte = SimpleFactory.createInstance("Latte");
latte.details();
Coffee americano = SimpleFactory.createInstance("Americano");
americano.details();
Coffee nescafe = SimpleFactory.createInstance("Nescafe");
nescafe.details();
}
}
简单工厂模式在实际使用过程中,对产品部分来说是符合开闭原则的,但是对于工厂部分,每增加一个新产品,都要在工厂类中增加相应的创建逻辑,这显然违背了开闭原则。
不知道设计模式六大原则的同学请自行补课
http://www.runoob.com/design-pattern/design-pattern-intro.html
-
工厂方法模式
意图:提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。
可以理解为不同地区只生产自己类型的咖啡,美国America只生产Americano,德国Germany只生产Latte和Nescafe。
具体实现:
产品基类及实现同上
定义一个工厂基类,(使用接口的方式会更好)
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:定义一个抽象咖啡工厂
*/
public abstract class CoffeeFactory {
/**
* 用于生产咖啡
* @return
*/
public abstract Coffee createCoffee(String type);
}
咖啡工厂的具体实现
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:美国咖啡工厂
*/
public class AmericaCoffeeFactory extends CoffeeFactory{
@Override
public Coffee createCoffee(String type) {
return new Americano();
}
}
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:德国咖啡工厂
*/
public class GermanyCoffeeFactory extends CoffeeFactory {
@Override
public Coffee createCoffee(String type) {
if (type.equals("Latte")) {
return new Latte();
} else if (type.equals("Nescafe")) {
return new Nescafe();
} else {
throw new RuntimeException("没有匹配到可实例化[" + type + "]对象");
}
}
}
使用
public class Test {
public static void main(String[] args) {
/**
* 工厂方法模式的使用方法
*/
CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
Coffee americaCoffees = americaCoffeeFactory.createCoffee("");
americaCoffees.details();
CoffeeFactory germanyCoffeeFactory = new GermanyCoffeeFactory();
Coffee latteCoffees = germanyCoffeeFactory.createCoffee("Latte");
latteCoffees.details();
Coffee nescafeCoffees = germanyCoffeeFactory.createCoffee("Nescafe");
nescafeCoffees.details();
}
}
工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品时,我们只需要增加一个具体的产品类和与之对应的具体工厂即可,无须修改原有系统。但是由于每新增一个新产品时就需要增加两个类,这样势必会导致系统的复杂度增加。
-
抽象工厂模式
场景:当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。
意图:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。抽象工厂为不同产品族的对象创建提供接口。
关键点在于如何在一个工厂里聚合多个同类产品。
具体实现:
抽象出饮料制造工厂
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:
*/
public interface AbstractDrinksFactory {
/**
* 制造咖啡
* @return
*/
Coffee createCoffee();
/**
* 制造碳酸饮料
* @return
*/
Sodas createSodas();
/**
* 制造茶
* @return
*/
Tea createTea();
}
饮料工厂的具体实现
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:美国饮料工厂
*/
public class AmericaDrinksFactory implements AbstractDrinksFactory{
@Override
public Coffee createCoffee() {
return new Latte();
}
@Override
public Sodas createSodas() {
return new CocaCola();
}
@Override
public Tea createTea() {
return null;
}
}
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:中国饮料工厂
*/
public class ChinaDrinksFactory implements AbstractDrinksFactory{
@Override
public Coffee createCoffee() {
return new Latte();
}
@Override
public Sodas createSodas() {
return new CocaCola();
}
@Override
public Tea createTea() {
return new Dragon_Well();
}
}
使用
/**
* @Author: chichapaofan
* @CreateDate: 2018/10/24
* @Description:
*/
public class Test {
public static void main(String[] args) {
/**
* 抽象工厂测试
*/
AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory();
Coffee coffee = chinaDrinksFactory.createCoffee();
Sodas sodas = chinaDrinksFactory.createSodas();
Tea tea = chinaDrinksFactory.createTea();
if (coffee != null) {
coffee.details();
}
if (sodas != null) {
sodas.details();
}
if (tea != null) {
tea.details();
}
}
}
抽象工厂模式最主要的优点就是可以在类的内部对产品族进行约束,而不必专门引入一个新的类来进行管理。
当然抽象工厂模式的缺点也非常明显,那就是产品族的不易扩展,使产品族中每需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
参考文章:
http://www.runoob.com/design-pattern/abstract-factory-pattern.html
https://www.cnblogs.com/zailushang1996/p/8601808.html
https://www.cnblogs.com/carryjack/p/7709861.html