总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
这里我们先来聊聊工厂方法模式。
简单工厂模式、工厂方法模式、抽象工厂模式,都是属于创建型设计模式。严格上来说,简单工厂模式不属于23设计模式之一,因为它违背了开闭原则。
先弄一个冰淇淋接口+3个口味的冰淇淋实现类
/**
* 冰淇淋接口、没有具体口味
* @author xingyanan01-lhq
*/
public interface IceCream {
public void makeIceCream();
}
/**
* 苹果口味冰淇淋
* @author xingyanan01-lhq
*/
public class AppleIceCream implements IceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个苹果口味冰淇淋");
}
}
/**
* 橘子口味冰淇淋
* @author xingyanan01-lhq
*/
public class OrangeIceCream implements IceCream {
@Override
public void makeIceCream() {
System.out.println("制作一个橘子口味冰淇淋");
}
}
/**
* 香蕉口味冰淇淋
* @author xingyanan01-lhq
*/
public class BananaIceCream implements IceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个香蕉口味冰淇淋");
}
}
造一个冰淇淋工厂,根据不同口味口令KEY来判断具体生产什么口味的冰淇淋
/**
* 冰淇淋工厂,根据传递的key来返回不同的冰淇淋类
* @author xingyanan01-lhq
*/
public class IceCreamFactory {
//这里注意一下,用静态static方法
public static IceCream creamIceCream(String key){
IceCream iceCream = null;
if("apple".equals(key)) {
iceCream = new AppleIceCream();
}
if("orange".equals(key)) {
iceCream = new OrangeIceCream();
}
if("banana".equals(key)) {
iceCream = new BananaIceCream();
}
return iceCream;
}
}
具体实现:
/**
* 客户端执行
* @author xingyanan01-lhq
*/
public static void main(String[] args) {
// 我告诉工厂,我想要个苹果口味冰淇淋
IceCream appleIceCream = IceCreamFactory.creamIceCream("apple");
appleIceCream.makeIceCream();
// 我告诉工厂,我想要个橘子口味冰淇淋
IceCream orangeIceCream = IceCreamFactory.creamIceCream("orange");
orangeIceCream.makeIceCream();
// 我告诉工厂,我想要个香蕉口味冰淇淋
IceCream bananaIceCream = IceCreamFactory.creamIceCream("banana");
bananaIceCream.makeIceCream();
}
这里我们用一个冰淇淋工厂管理所有口味的冰淇淋,我们只需要new一个冰淇淋工厂,就能通过key获取所有口味的冰淇淋。
简单工厂模式确实很方便,但是每次新增一个口味的冰淇淋都需要改动整个工厂的原有代码。
那不如我们一个冰淇淋工厂只生产一种冰淇淋,需要新增口味就直接新建一个工厂。
还是要弄一个冰淇淋接口+3个口味的冰淇淋实现类
/**
* 冰淇淋接口、没有具体口味
* @author xingyanan01-lhq
*/
public interface IceCream {
public void makeIceCream();
}
/**
* 苹果口味冰淇淋
* @author xingyanan01-lhq
*/
public class AppleIceCream implements IceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个苹果口味冰淇淋");
}
}
/**
* 橘子口味冰淇淋
* @author xingyanan01-lhq
*/
public class OrangeIceCream implements IceCream {
@Override
public void makeIceCream() {
System.out.println("制作一个橘子口味冰淇淋");
}
}
/**
* 香蕉口味冰淇淋
* @author xingyanan01-lhq
*/
public class BananaIceCream implements IceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个香蕉口味冰淇淋");
}
}
造一个冰淇淋工厂接口+3个冰淇淋对应口味的冰淇淋工厂
/**
* 冰淇淋工厂接口,没有具体口味
* @author xingyanan01-lhq
*/
public interface IceCreamFactory {
public IceCream creamIceCream();
}
/**
* 苹果冰淇淋工厂
* @author xingyanan01-lhq
*/
public class AppleIceCreamFactory implements IceCreamFactory{
@Override
public IceCream creamIceCream() {
return new AppleIceCream();
}
}
/**
* 橘子冰淇淋工厂
* @author xingyanan01-lhq
*/
public class OrangeIceCreamFactory implements IceCreamFactory{
@Override
public IceCream creamIceCream() {
return new OrangeIceCream();
}
}
/**
* 香蕉冰淇淋工厂
* @author xingyanan01-lhq
*/
public class BananaIceCreamFactory implements IceCreamFactory{
@Override
public IceCream creamIceCream() {
return new BananaIceCream();
}
}
具体实现:
/**
* 客户端执行
* @author xingyanan01-lhq
*/
public static void main(String[] args) {
// 我去苹果口味冰淇淋工厂,要一个冰淇淋
AppleIceCreamFactory appleIceCreamFactory = new AppleIceCreamFactory();
IceCream appleIceCream = appleIceCreamFactory.creamIceCream();
appleIceCream.makeIceCream();
// 我去橘子口味冰淇淋工厂,要一个冰淇淋
OrangeIceCreamFactory orangeIceCreamFactory = new OrangeIceCreamFactory();
IceCream orangeIceCream = orangeIceCreamFactory.creamIceCream();
orangeIceCream.makeIceCream();
// 我去香蕉口味冰淇淋工厂,要一个冰淇淋
BananaIceCreamFactory bananaIceCreamFactory = new BananaIceCreamFactory();
IceCream bananaIceCream = bananaIceCreamFactory.creamIceCream();
bananaIceCream.makeIceCream();
}
这里我们是每个口味的冰淇淋都有对应的工厂,后续如果想新增一个口味的冰淇淋,只需要加一个工厂,无需改动其它的已有的工厂
看到这里你可能会有疑惑,这样的话一个口味的冰淇淋对应一个工厂,我还用工厂干嘛?直接new冰淇淋不好吗?
别着急,让我们带着这个疑问往后看~
如果现在冰淇淋有规格要求了,有大冰淇淋小冰淇淋的,这可咋办?
还是要弄1个大冰淇淋接口+1个小冰淇淋接口+对应3个口味的6个具体冰淇淋实现类
/**
* 大冰淇淋、没有具体口味
* @author xingyanan01-lhq
*/
public interface BigIceCream {
public void makeIceCream();
}
/**
* 小冰淇淋、没有具体口味
* @author xingyanan01-lhq
*/
public interface SmallIceCream {
public void makeIceCream();
}
/**
* 大苹果口味冰淇淋
* @author xingyanan01-lhq
*/
public class BigAppleIceCream implements BigIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个大号苹果口味冰淇淋");
}
}
/**
* 小苹果口味冰淇淋
* @author xingyanan01-lhq
*/
public class SmallAppleIceCream implements SmallIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个小号苹果口味冰淇淋");
}
}
/**
* 大橘子口味冰淇淋
* @author xingyanan01-lhq
*/
public class BigOrangeIceCream implements BigIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个大号橘子口味冰淇淋");
}
}
/**
* 小橘子口味冰淇淋
* @author xingyanan01-lhq
*/
public class SmallOrangeIceCream implements SmallIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个小号橘子口味冰淇淋");
}
}
/**
* 大香蕉口味冰淇淋
* @author xingyanan01-lhq
*/
public class BigBananaIceCream implements BigIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个大号香蕉口味冰淇淋");
}
}
/**
* 小香蕉口味冰淇淋
* @author xingyanan01-lhq
*/
public class SmallBananaIceCream implements SmallIceCream{
@Override
public void makeIceCream() {
System.out.println("制作一个小号香蕉口味冰淇淋");
}
}
定义一个冰淇淋工厂接口+三个口味的冰淇淋工厂实现类
/**
* 冰淇淋工厂接口,没有具体口味
* @author xingyanan01-lhq
*/
public interface IceCreamFactory {
public BigIceCream creamBigIceCream();
public SmallIceCream creamSmallIceCream();
}
/**
* 苹果冰淇淋工厂
* @author xingyanan01-lhq
*/
public class AppleIceCreamFactory implements IceCreamFactory{
@Override
public BigIceCream creamBigIceCream() {
return new BigAppleIceCream();
}
@Override
public SmallIceCream creamSmallIceCream() {
return new SmallAppleIceCream();
}
}
/**
* 橘子冰淇淋工厂
* @author xingyanan01-lhq
*/
public class OrangeIceCreamFactory implements IceCreamFactory{
@Override
public BigIceCream creamBigIceCream() {
return new BigOrangeIceCream();
}
@Override
public SmallIceCream creamSmallIceCream() {
return new SmallOrangeIceCream();
}
}
/**
* 香蕉冰淇淋工厂
* @author xingyanan01-lhq
*/
public class BananaIceCreamFactory implements IceCreamFactory{
@Override
public BigIceCream creamBigIceCream() {
return new BigBananaIceCream();
}
@Override
public SmallIceCream creamSmallIceCream() {
return new SmallBananaIceCream();
}
}
具体实现:
/**
* 客户端执行
* @author xingyanan01-lhq
*/
public static void main(String[] args) {
// 我去苹果口味冰淇淋工厂
AppleIceCreamFactory appleIceCreamFactory = new AppleIceCreamFactory();
// 要一个大冰淇淋
BigIceCream bigAppleIceCream = appleIceCreamFactory.creamBigIceCream();
bigAppleIceCream.makeIceCream();
// 要一个小冰淇淋
SmallIceCream smallAppleIceCream = appleIceCreamFactory.creamSmallIceCream();
smallAppleIceCream.makeIceCream();
// 我去橘子口味冰淇淋工厂
OrangeIceCreamFactory orangeIceCreamFactory = new OrangeIceCreamFactory();
// 要一个大冰淇淋
BigIceCream bigOrangeIceCream = orangeIceCreamFactory.creamBigIceCream();
bigOrangeIceCream.makeIceCream();
// 要一个小冰淇淋
SmallIceCream smallOrangeIceCream = orangeIceCreamFactory.creamSmallIceCream();
smallOrangeIceCream.makeIceCream();
// 我去香蕉口味冰淇淋工厂
BananaIceCreamFactory bananaIceCreamFactory = new BananaIceCreamFactory();
// 要一个大冰淇淋
BigIceCream bigBananaIceCream = bananaIceCreamFactory.creamBigIceCream();
bigBananaIceCream.makeIceCream();
// 要一个小冰淇淋
SmallIceCream smallBananaIceCream = bananaIceCreamFactory.creamSmallIceCream();
smallBananaIceCream.makeIceCream();
}
可以看到,之所以叫抽象工厂,是因为和工厂方法相比,这里有多个抽象产品类存在(即大份的冰激凌和小份的冰激凌),每个抽象产品类可以派生出多个具体的产品,生产的是系列产品,其工厂接口相对于工厂方法模式而言,是有多个方法的,用来生产不同的抽象产品。
不过,我们也很容易看出,抽象工厂模式的弊端。比如现在,商场想要提供的是大、中、小三种系列产品,那么现在,需要改动的代码就有点多了。首先需要创建一个接口,用来生产中份的冰激凌,然后还要实现具体的类,还需要修改工厂接口,并修改具体的工厂类。
而且我们还可以看到,当业务逻辑复杂时,我们可以根据工厂类的定义,将很多个有逻辑关系的实现类归纳在一起,可能如果实现类只有10个8个,会觉得创建工厂没有什么必要,但是一旦实现类成百上千,这种工厂模式能很清晰的将实现类合并在一个工厂中。
回到之前的问题,我实体类很多,我每一个都能记得住,我直接new不香吗?为什么要用工厂模式来创建实体类?
如果你写了一个workUtil.java,里面放了很多很多很多你平时工作中需要用的业务处理方法,这个类有上万行代码。
这样代码可读性很差很差,而且每一次new这个对象需要做的初始化工作很多。
将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java 面向对象的原则,面向对象的封装(Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间耦合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。
如果你根据你的工作需求将需要用的方法分类,创建一个workUtil接口,并根据业务场景分成了多个具体实现类(logWorkUtil、sqlWorkUtil、javaWorkUtil等等),
这样我们就能尽可能的将代码拆分,并且通过工厂模式来统一管理这些实现类快捷创建对应实现类,减少后期维护的代码修改量,也降低了耦合度。