设计模式之工厂模式Factory

工厂模式:创建对象的工厂

为什么要用工厂模式:

1,解耦
通过工厂模式可以把对象的创建和使用过程分离。
2,减少代码量,易于维护
如果我们直接new一个对象时,如果需要的对象构造方法比较复杂,那么可能需要一连串的代码去创建对象,如果在别的类中又需要创建该对象,那么代码的重复度肯定不小。通过工厂模式的话,我们把对象创建的具体逻辑给隐藏起来了,交给工厂统一管理,这样不仅减少了代码量,以后如果想改代码的话,只需要改一处即可,也方便我们日常的维护。

假如说,这个工厂现在用来生成蛋糕,下面先来看三个问题(弄懂这三个问题工厂模式翻篇)

1,任意定制蛋糕口味

2,任意定制蛋糕口味生产过程

3,任意定制生产蛋糕产品一族

 

一,我们先看第一个问题(任意定制蛋糕口味)

首先要有蛋糕的父类或者接口

package com.zl.factory;

public interface Cake {

    void eat();

}

其次是具体的实现类

package com.zl.factory;

//巧克力口味蛋糕
public class ChocolateCake implements Cake {
    @Override
    public void eat() {
        System.out.println("eat chocolateCake........");
    }
}
package com.zl.factory;

//水果味蛋糕
public class FruitCake implements Cake {
    @Override
    public void eat() {
        System.out.println("eat fruitCake..........");
    }
}

最后就是运用到具体环境中,这里以测试类代替

package com.zl.factory;

public class Test {
    public static void main(String[] args) {
        //定制水果味蛋糕
        Cake cake = new FruitCake();
        cake.eat();

    }
}

其实第一个问题就是Java多态

 

二,下面来第二个问题(任意定制蛋糕口味生产过程)

还是一样,先来几个具体的不同口味蛋糕

package com.zl.factory;

//水果味蛋糕
public class FruitCake{

    public void eat() {
        System.out.println("eat fruitCake..........");
    }
}
package com.zl.factory;

//巧克力口味蛋糕
public class ChocolateCake {
    
    public void eat() {
        System.out.println("eat chocolateCake........");
    }
}

来一个蛋糕厂

package com.zl.factory;

public class SimpleCakeFactory {

    public FruitCake createFruitCake(){
        //before processing前置业务,如日志记录
        return new FruitCake();
    }

    public ChocolateCake createChocolateCake(){
        //before processing前置业务,如日志记录
        return new ChocolateCake();
    }

}

最后运用到具体环境中,还是以测试类代替

package com.zl.factory;

public class Test {
    public static void main(String[] args) {

        //生产水果蛋糕
        FruitCake fruitCake = new SimpleCakeFactory().createFruitCake();
        fruitCake.eat();

        //生产巧克力蛋糕
        ChocolateCake chocolateCake = new SimpleCakeFactory().createChocolateCake();
        chocolateCake.eat();

    }
}

这种也就是我们说的简单工厂,不过这种工厂比较混乱,什么蛋糕都生产,不专一

 

于是就有了我们说的工厂方法,为每一种口味蛋糕单一生产,废话少说,上代码

package com.zl.factory;

public class FruitCakeFactory {

    public FruitCake create(){
        //before processing前置业务,如日志记录
        return new FruitCake();
    }

}
package com.zl.factory;

public class ChocolateCakeFactory {

    public ChocolateCake create(){
        //before processing前置业务,如日志记录
        return new ChocolateCake();
    }
}

 

三,最后一个问题(任意定制生产蛋糕产品一族)

我们先来看一下传统的方法,假如我们要生产蛋糕,蛋糕蜡烛,蛋糕包装等蛋糕一族。

先来三个具体实现类

 

package com.zl.abstractFactory;

//水果味蛋糕
public class FruitCake {

    public void eat() {
        System.out.println("eat fruitCake..........");
    }
}
package com.zl.abstractFactory;

//红色蜡烛
public class RedCandle {

    public void see(){
        System.out.println("it is red candle");
    }

}
package com.zl.abstractFactory;

//简约的包装风格
public class SimpleStyle {

    public void style(){
        System.out.println("it is simple...");
    }

}

具体客户端运用

package com.zl.abstractFactory;

public class Test {
    public static void main(String[] args) {

        FruitCake cake = new FruitCake();
        cake.eat();
        RedCandle candle = new RedCandle();
        candle.see();
        SimpleStyle style = new SimpleStyle();
        style.style();

    }
}

假如我们要换一个蛋糕套餐,要巧克力口味的,要蓝色的蜡烛和别的类型包装,上面的运用都要改

下面运用工厂进行改进

首先,先来抽象的产品,然后让具体的产品去继承即可(产品继承部分,代码省略)

package com.zl.abstractFactory;

public abstract class Cake {

    abstract void eat();

}
package com.zl.abstractFactory;

public abstract class Candle {
   
    public abstract void see();
}
package com.zl.abstractFactory;

public abstract class Style {

    public abstract void style();

}

其次,用抽象的工厂生产抽象的产品

package com.zl.abstractFactory;

public abstract class AbstractFactory {

    abstract Cake createCake();
    abstract Candle createCandle();
    abstract Style createStyle();

}

最后按照产品族去生产(继承abstractFactory),比如说生产(水果味,红色蜡烛,简约包装风格)这一族蛋糕,我们命名为FirstProductCake

package com.zl.abstractFactory;

public class FirstProductCake extends  AbstractFactory{
    @Override
    Cake createCake() {
        return new FruitCake();
    }

    @Override
    Candle createCandle() {
        return new RedCandle();
    }

    @Override
    Style createStyle() {
        return new SimpleStyle();
    }
}

具体运用

package com.zl.abstractFactory;

public class Test {
    public static void main(String[] args) {

        AbstractFactory factory = new FirstProductCake();

        Cake cake = factory.createCake();
        cake.eat();
        Candle candle = factory.createCandle();
        candle.see();
        Style style = factory.createStyle();
        style.style();


    }
}

当我们要不同的蛋糕套餐时,只需要去定义不同的生产族即可(继承abstractFactory)

这就是我们说的抽象工厂

 

可能到这里有些人有疑问,定义抽象产品直接用接口可以吗?   答案是可以的。这里就要抠语义了,蛋糕,蜡烛这些都是现实生活中存在的的东西,我们只是把它抽象出来,故用抽象类更适合。

比如说有个东西是“可移动的”,它可以是吃的东西,也可以是交通工具,也可以是动物,此时定义接口更合适。

(通俗一点,名词适合用抽象类,形容词适合用接口)

 

抽象工厂具体运用:比如我们开发了一款游戏,要为不同的英雄设计不同的皮肤,当我们更换英雄皮肤时,英雄外观会发生改变,英雄攻击会有相应的攻击特效,还有回城特效,这就相当于皮肤产品一族。

 

最后对比工厂方法和抽象工厂:

(1)工厂方法适合在产品维度上面去增加修改产品

(2)抽象工厂适合在产品族维度上面扩展产品套餐

(3)各有各的优势和不足

 

那有没有更完美的工厂,在这两个维度上面都可以扩展,答案,有。

那就是spring bean工厂,en。。。等读了源码在来分析......

 

posted @ 2020-06-18 22:42  风子磊  阅读(212)  评论(0编辑  收藏  举报