目录
一:GoF之工厂模式
1. 工厂模式的三种形态
2. 简单工厂模式
3. 工厂方法模式
4. 抽象工厂模式(了解)
(1)GoF(Gang of Four),中文名——四人组。
(2)设计模式:一种可以被重复利用的解决方案。
(3)《Design Patterns: Elements of Reusable Object-Oriented Software》(即《设计模式》一书),1995年由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著。这几位作者常被称为"四人组(Gang of Four)"。
(4)该书中描述了23种设计模式,我们平常所说的设计模式就是指这23种设计模式;不过除了GoF23种设计模式之外,还有其它的设计模式,比如:JavaEE的设计模式(DAO模式、MVC模式等)!
GoF23种设计模式可分为三大类:
创建型(5个):解决对象创建问题
- 单例模式
- 原型模式
- 建造者模式
- 抽象工厂模式
- 工厂方法模式
结构型(7个):一些类或对象组合在一起的经典结构
- 代理模式
- 桥接模式
- 外观模式
- 享元模式
- 组合模式
- 适配器模式
- 装饰模式
行为型(11个):解决类或对象之间的交互问题
- 策略模式
- 解释器模式
- 中介者模式
- 访问者模式
- 状态模式
- 备忘录模式
- 命令模式
- 迭代子模式
- 观察者模式
- 责任链模式
- 模板方法模式
(1)工厂模式是解决对象创建问题的,所以工厂模式属于创建型设计模式!这里为什么学习工厂模式呢?这是因为Spring框架底层使用了大量的工厂模式!
(2)工厂模式通常有三种形态:
- 第一种:简单工厂模式(Simple Factory):不属于23种设计模式之一。简单工厂模式又叫做:静态工厂方法模式。简单工厂模式是工厂方法模式的一种特殊实现。
- 第二种:工厂方法模式(Factory Method):是23种设计模式之一。
- 第三种:抽象工厂模式(Abstract Factory):是23种设计模式之一。
(1)简单工厂模式是工厂方法模式的一种特殊实现,又被称为:静态工厂方法模式!
(2)简单工厂模式的角色包括三个:
- 抽象产品 角色
- 具体产品 角色
- 工厂类 角色
抽象产品 角色
Weapon武器类
package com.bjpowernode.simple.factory;
// 抽象产品角色
public abstract class Weapon {
// 所有的武器都可以攻击。
public abstract void attack();
}
具体产品 角色
Tank坦克类
package com.bjpowernode.simple.factory;
// 具体产品角色
public class Tank extends Weapon{
@Override
public void attack() {
System.out.println("坦克开炮!!!");
}
}
Fighter战斗机类
package com.bjpowernode.simple.factory;
// 具体产品角色
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("战斗机抛下小男孩!!!!");
}
}
Dagger匕首类
package com.bjpowernode.simple.factory;
// 具体产品角色
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!!!");
}
}
工厂类 角色
WeaponFactory武器工厂类
①是静态方法,要获取什么产品?就看你传什么参数,传TANK获取坦克,传DAGGER获取匕首,传FIGHTER获取战斗机
②简单工厂模式中有一个静态方法,所以被称为:静态工厂方法模式。
package com.bjpowernode.simple.factory;
// 工厂类角色
public class WeaponFactory {
public static Weapon get(String weaponType){
if ("TANK".equals(weaponType)) {
return new Tank();
} else if ("DAGGER".equals(weaponType)) {
return new Dagger();
} else if ("FIGHTER".equals(weaponType)) {
return new Fighter();
} else {
throw new RuntimeException("不支持该武器的生产");
}
}
}
客户端程序---进行测试
①对于客户端来说,坦克的生产细节(创建对象),并不需要关心,只需要向工厂索要即可!
②简单工厂模式达到了什么呢?职责分离,客户端不需要关心产品的生产细节;客户端只负责消费,工厂类负责生产;一个负责生产,一个负责消费;生产者和消费者分离了,这就是简单工厂模式的作用。
package com.bjpowernode.simple.factory;
// 这是客户端程序
public class Test {
public static void main(String[] args) {
// 需要坦克
Weapon tank = WeaponFactory.get("TANK");
tank.attack();
// 需要匕首
Weapon dagger = WeaponFactory.get("DAGGER");
dagger.attack();
// 需要战斗机
Weapon fighter = WeaponFactory.get("FIGHTER");
fighter.attack();
}
}
总结:Spring中的BeanFactory就使用了简单工厂模式!
(1)简单工厂模式解决什么问题(优点)呢?
客户端程序不需要关心对象的创建细节,需要哪个对象时,只需要向工厂索要即可,初步实现了责任的分离。客户端只负责“消费”,工厂负责“生产”;生产和消费分离!(2)简单工厂模式的缺点?
①假设现在需要扩展一个新的武器产品,WeaponFactory工厂类的代码是需要修改的,显然违背了OCP原则!
②工厂类的责任比较重大,不能出现任何问题,因为这个工厂类负责所有产品的生产,称为全能类,或者叫做上帝类。这个工厂类一旦出问题,整个系统必然全部瘫痪!
(1)工厂方法模式可以解决简单工厂模式当中的OCP问题。怎么解决的?一个工厂对应生产一种产品;这样工厂就不是全能类了,不是上帝类了;另外,也可以符合OCP原则。
(2)工厂方法模式的角色包括四个:
- 抽象产品 角色
- 具体产品 角色
- 抽象工厂 角色
- 具体工厂 角色
抽象工厂 角色
package com.bjpowernode.factory.method;
public abstract class WeaponFactory {
// 这个方法不是静态的,是实例方法。
public abstract Weapon get();
}
具体工厂 角色---继承抽象工厂,一个工厂对应生产一种产品
DaggerFactory生产匕首的专有工厂
package com.bjpowernode.factory.method;
// 具体工厂角色
public class DaggerFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Dagger();
}
}
TankFactory生产坦克的专有工厂
package com.bjpowernode.factory.method;
// 具体工厂角色
public class TankFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Tank();
}
}
客户端程序---进行测试
注:这里还是创建对象了,所以我们使用上面的简单工厂模式在抽象出一个大工厂,来管理创建对象的问题!这里暂时只考虑结局OCP的问题!
package com.bjpowernode.factory.method;
// 客户端程序
public class Test {
public static void main(String[] args) {
WeaponFactory weaponFactory = new DaggerFactory();
Weapon dagger = weaponFactory.get();
dagger.attack();
WeaponFactory weaponFactory1 = new TankFactory();
Weapon gun = weaponFactory1.get();
gun.attack();
}
}
总结:
(1)工厂方法模式的缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂类,使得系统中类的个数成倍增加(存在类爆炸问题),在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖!(2)工厂方法模式的优点:
①当你扩展一个产品的时候,符合OCP原则(扩展性高),因为只需要添加两个类,一个类是具体产品类,一个类是具体工厂类,都是添加类,没有修改之前的代码,所以符合OCP!
②一个调用者想创建一个对象,只要知道其名称就可以了,屏蔽产品的具体实现,调用者只关心产品的接口。
(1)Spring底层并没有调用抽象工厂模式,所以这部分可以暂时为了解!
(2)抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类!
(3)抽象工厂模式特点:
①抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。
②抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
③抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。
④它有多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,一个抽象工厂类,可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类的实例。
⑤每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结果。
(4)抽象工厂中包含4个角色:
- 抽象产品角色
- 具体产品角色
- 抽象工厂角色
- 具体工厂角色
第一部分:武器产品
Weapon类武器产品族
package com.powernode.product;
// 武器产品族
public abstract class Weapon {
// 所有武器都可以攻击
public abstract void attack();
}
Gun类武器产品族中的产品等级1
package com.powernode.product;
// 武器产品族中的产品等级1
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("开枪射击!");
}
}
Dagger类武器产品族中的产品等级2
package com.powernode.product;
// 武器产品族中的产品等级2
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!");
}
}
第二部分:水果产品
Fruit类水果产品族
package com.powernode.product;
// 水果产品族
public abstract class Fruit {
// 所有果实都有一个成熟周期。
public abstract void ripeCycle();
}
Orange类水果产品族中的产品等级1
package com.powernode.product;
// 水果产品族中的产品等级1
public class Orange extends Fruit{
@Override
public void ripeCycle() {
System.out.println("橘子的成熟周期是10个月");
}
}
Apple类水果产品族中的产品等级2
package com.powernode.product;
// 水果产品族中的产品等级2
public class Apple extends Fruit{
@Override
public void ripeCycle() {
System.out.println("苹果的成熟周期是8个月");
}
}
第三部分:抽象工厂类
package com.powernode.factory;
import com.powernode.product.Fruit;
import com.powernode.product.Weapon;
// 抽象工厂
public abstract class AbstractFactory {
// 两个实例方法
public abstract Weapon getWeapon(String type);
public abstract Fruit getFruit(String type);
}
第四部分:具体工厂类
武器族工厂
package com.powernode.factory;
import com.powernode.product.Dagger;
import com.powernode.product.Fruit;
import com.powernode.product.Gun;
import com.powernode.product.Weapon;
// 武器族工厂
public class WeaponFactory extends AbstractFactory{
public Weapon getWeapon(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Gun".equals(type)) {
return new Gun();
} else if ("Dagger".equals(type)) {
return new Dagger();
} else {
throw new RuntimeException("无法生产该武器");
}
}
@Override
public Fruit getFruit(String type) {
return null;
}
}
水果族工厂
package com.powernode.factory;
import com.powernode.product.*;
// 水果族工厂
public class FruitFactory extends AbstractFactory{
@Override
public Weapon getWeapon(String type) {
return null;
}
public Fruit getFruit(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Orange".equals(type)) {
return new Orange();
} else if ("Apple".equals(type)) {
return new Apple();
} else {
throw new RuntimeException("果园不产这种水果");
}
}
}
第五部分:客户端程序
package com.powernode.client;
import com.powernode.factory.AbstractFactory;
import com.powernode.factory.FruitFactory;
import com.powernode.factory.WeaponFactory;
import com.powernode.product.Fruit;
import com.powernode.product.Weapon;
public class Client {
public static void main(String[] args) {
// 客户端调用方法时只面向AbstractFactory调用方法。
AbstractFactory factory = new WeaponFactory(); // 注意:这里的new WeaponFactory()可以采用 简单工厂模式 进行隐藏。
Weapon gun = factory.getWeapon("Gun");
Weapon dagger = factory.getWeapon("Dagger");
gun.attack();
dagger.attack();
AbstractFactory factory1 = new FruitFactory(); // 注意:这里的new FruitFactory()可以采用 简单工厂模式 进行隐藏。
Fruit orange = factory1.getFruit("Orange");
Fruit apple = factory1.getFruit("Apple");
orange.ripeCycle();
apple.ripeCycle();
}
}
总结:
(1)优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
(2)缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在AbstractFactory里加代码,又要在具体的里面加代码。