静态工厂
在最早的《DesignPattern》这本书中 静态工厂是没有的 工厂系列就两个模式 工厂方法和抽象工厂,但是也有人说静态工厂是工厂模式
什么是工厂?
1.任何可以产生(new)对象的方法或类,都可以称之为工厂
2.看到1个方法 它的返回值return是1个对象 就可以称之为1个工厂
所以单例也是一种工厂,单例模式的 getInstance 就是拿到1个对象 所以有人把单例模式 称为静态工厂
为什么要工厂? 我们已经可以new产生对象了,为什么还要工厂?
工厂可以灵活控制生产过程,可以加权限、修饰decorate、日志log等
我们先写1个类 Car
public class Car {
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
然后我们再创建1个Main类 new出来1个Car
public class Main {
public static void main(String[] args) {
Car c = new Car();
c.go();
}
}
现在开的是Car车 我明天想开Plane飞机怎么办? 可以定制交通工具(实现类 )吗?
我们当然可以再创建1个Plane飞机类,然后main方法去创建1个飞机
public class Plane {
public void go(){
System.out.println("Plane fly xixixixixixixi....");
}
}
public class Main {
public static void main(String[] args) {
// Car c = new Car();
// c.go();
Plane p = new Plane();
p.go();
}
}
如果我以后想开火车Train,船Boat等等?难道还是像这样 1个1个扩展吗?代码太多了,既要新建1个类,还要修改main方法里的内容,我想少点,怎么办?
我们可以创建1个接口Moveable ,其他的所有交通工具去实现这个接口
public interface Moveable {
void go();
}
public class Plane implements Moveable{
public void go(){
System.out.println("Plane fly xixixixixixixi....");
}
}
public class Car implements Moveable{
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
这样main方法可以利用多态,只用改new后面的类就行了,不管调用
public class Main {
public static void main(String[] args) {
Moveable m = new Plane();
m.go();
}
}
代码只用修改1个地方,不用像第1种方法,要删除修改至少2段
需求又来了,我想任意定制旅途过程 怎么办?
实际中的应用 我new 1个交通工具后 我要求你必须控制权限 那么我的代码要修改在Plane类里 必须要来回的变;我可以把 产生对象的这个过程 不用new 我交给1个工厂方法
1.简单工厂VehicleFatory
创建1个VehicleFactory类 里面有几个方法 比如返回Car对象的 createCar()方法 在这个方法里面 我们可以对它进行日志处理 权限处理等;而且VehicleFactory类除了 产生Car外 还可以产生Plane等
public class VehicleFactory {
public Car createCar(){
return new Car();
}
public Plane createPlane(){
return new Plane();
}
}
但是这种方法不太好 因为它虽然很简单 但是可扩展性不太好 当我们新添加1种交通工具 火车train的时候 里面就要新添加新的createTrain方法 而且里面的 权限处理的操作也是写死的
针对每个产品做1个工厂
对于Car来说 我加1个CarFactory类
public class CarFactory {
public Car createCar(){
System.out.println("a car created!");
return new Car();
}
}
如果我们想用CarFactory的话 main方法要这样写
public class Main {
public static void main(String[] args) {
Moveable m = new CarFactory().createCar();
m.go();
}
}
想来个Plane的话 就写个PlaneFactory().createPlane() 想来个broom的话 就写个BroomFactory().createBroom()
但是问题来了 当我们要添加一种新的交通工具的时候 我们首先得把它的工厂做出来PlaneFactory,broomFactory 接下来 我还要把代码改一下 更麻烦
总结一下:任意定制交通工具,我们可以 继承Moveable;任意定制生产过程,我们可以Moveable XXXFactory.create()
2.抽象工厂
因为叫抽象工厂,所以是任意定制产品一族(不只1种系列产品),叫abstractFactory 更加抽象这个问题。
比如:现在是这样的 ,作为1个司机 我开着一辆车 车还在跑,然后这个司机,他手里还持有1个武器AK47 就叫AK47类,他还可以吃一点面包Bread 有个面包类
AK47类可以开枪,Brand类可以打印品牌
public class AK47 {
public void shoot(){
System.out.println("tutututututu.....");
}
}
public class Brand {
public void printName(){
System.out.println("wdm");
}
}
那么这样我就模拟了 很多类产品 Car,AK47,Bread ,其实这个是 产品簇的概念 我们有没有一种方式 可以灵活的指定 来扩展新的产品簇,比如现在我来一个人是魔法师 他骑的是扫帚Broom 吃的是蘑菇Mushroom 它的魔法棒MagicStick可以发电 这样当新的产品加进来的时候 代码不用改太多呢?
可以的 我们可以new 1个AbstractFactory. 这个抽象工厂 可以生产 1系列产品 他可以生产食物,武器,交通工具
public abstract class Food {
abstract void printName();
}
public abstract class Weapon {
abstract void shoot();
}
public abstract class Vehicle {
abstract void go();
}
我们假设 这个抽象工厂会产生 3类产品;第1类是Food,第2类是Vehicle,第3类是Weapon,他们都可以返回对应的对象,可以生成抽象的产品
public abstract class AbstractFactory {
abstract Food createFood();
abstract Vehicle createVehicle();
abstract Weapon createWeapon();
}
然后我们让所有的不同类别的产品 去继承
现代人的工具簇就是 Weapon对应AK47,Food对应Bread,Vehicle对应Car
//现代人的工具包
public class Car extends Vehicle{
public void go() {
System.out.println("Car go wuwuwuwuwu.....");
}
}
public class Brand extends Food{
public void printName(){
System.out.println("wdm");
}
}
public class AK47 extends Weapon{
public void shoot(){
System.out.println("tutututututu.....");
}
}
我们做1个现代工厂ModernFactory,帮我们去生产这些东西,而不必自己去new
public class ModernFactory extends AbstractFactory {
@Override
Food createFood() {
return new Brand();
}
@Override
Vehicle createVehicle() {
return new Car();
}
@Override
Weapon createWeapon() {
return new AK47();
}
}
魔法师的工具簇就是 Weapon对应MagStick,Food对应MushRoom,Vehicle对应Broom
//魔法师的工具包
public class Broom extends Vehicle {
public void go(){
System.out.println("Broom flying shushushus....");
}
}
public class MushRoom extends Food {
public void printName(){
System.out.println("毒蘑菇");
}
}
public class MagicStick extends Weapon{
public void shoot(){
System.out.println("dian dian dian dian....");
}
}
魔法师就是魔法工厂MagicFactory,帮我们去生产这些东西
public class MagicFactory extends AbstractFactory{
@Override
Food createFood() {
return new MushRoom();
}
@Override
Vehicle createVehicle() {
return new Broom();
}
@Override
Weapon createWeapon() {
return new MagicStick();
}
}
现在,我们main方法里面代码就简单了
之间我们需要1个1个new
Car c =new Car();
c.go();
AK47 w=new AK47();
w.shoot();
Bread b=new Bread();
b.printName();
现在不需要了 直接调用现代工厂里的方法就行
AbstractFactory f = new ModernFactory();
Vehicle c = f.createVehicle();
Weapon w = f.createWeapon();
Food b = f.createFood();
而且修改代码恨少,你想改成 魔法世界工厂 你就把new 后面改一下 下面的都不用改 new MagicFactory(),同理,火星世界 就改成火星一簇 写个MarsFactory 去实现里面的火星武器,食物,机器
注意:这个工厂里用的都是继承,不是接口的实现,因为工厂里的产生的食品一般是现实中存在的,但是它不是具体的某个食物,所以用抽象类比较合适,而接口更加侧重于这个东西的属性,moveable表示它这个东西可以动,comparable表示这个东西可以比较,所以从语义上用抽象类更加合适,形容词用接口,名词用抽象类
比较 工厂方法 和抽象工厂
工厂方法:在产品扩展时,比较方便
有Car 有Food 有AK47 以后比如说 还有帽子等等 非常方便
抽象工厂:然后 在产品簇上扩展比较方便 但是在产品上扩展不好扩展
所以这个是两个维度上的扩展,1个是产品一簇维度上 偏于扩展; 另一个是产品单一维度上 好扩展 都有自己的局限性
总结一下:
简单工厂vs静态工厂vs工厂方法vs抽象工厂
简单工厂:我们随便1个方法 只要createCar什么东西 返回的是1个对象 那么它就是简单工厂
静态工厂:静态的方法Static产生 比如单例的getInstance 就是1个静态工厂
工厂方法FactoryMethod:产品维度上扩展 很方便
抽象工厂:产品一簇进行扩展
我们经常可以用抽象工厂来完成一键风格替换,比如1个人物,我可以换它的声音,皮肤,动作等