java设计模式之工厂模式

背景

我认为无论学习什么模式,都应该首先知道它的由来(也就是为了解决什么样的问题)。这能为我们在学习它的时候提供一个方向,这很重要!
情景:富士康生产苹果手机,规格有13min、13、13pro、13proMax(它们大部分功能是一样的,但是配置和外形上有区别)。在不考虑任何模式的情况下,客户端1伪代码应该是这样的:

if(13min)
	new 13min()
if13new 13()
if13pro)
	new 13pro()

工厂设计模式:在某些情况下,对象的创建很复杂,可能需要某种程度的抽象,以便客户端代码不了解这些复杂性和内部实现细节。 在某些情况下,对象的创建在代码的各个部分中是分散的和重复的。

从这句话可以得出,如果实例化过于复杂(不是简单的,new 13());或者有多个调用者,多个new 语句,分散各处。那么我们就应该统一一个地方去创建对象,提供接口给调用者。
还有一个问题就是如果需要增加一个手机规格,那么所有调用者处都可能需要增加代码。

另一个问题是,客户端应用程序必须知道多少类型的具体类可以预先使用。

ps:这句话我就不是很理解,不管怎么说调用者都应该知道提供者能够提供什么类型啊。就好像给了我一个工具,还能不告诉我它干什么的?也许它指的是别的什么意思?

普通工厂

场景:富士康生产苹果手机,规格有13min、13、13pro(13proMax太贵了不考虑,哈哈!)。

不同规格苹果手机的共同接口:

public interface Iphone {

    String getName();

    void callNumber();

    void sendMessage(String message);

    void playgames(int gameName);
}

具体规格的手机实现类

iphone13:

public class Iphone13 implements Iphone{
    @Override
    public String getName() {
        return "iphone13";
    }

    @Override
    public void callNumber() {
        //todo 打电话
    }

    @Override
    public void sendMessage(String message) {
        //todo 发短信
    }

    @Override
    public void playgames(int gameName) {
        //todo 玩游戏
    }
}

iphone13min:

public class Iphone13min implements Iphone{
    @Override
    public String getName() {
        return "iphone13min";
    }

    @Override
    public void callNumber() {
        //todo 打电话
    }

    @Override
    public void sendMessage(String message) {
        //todo 发短信
    }

    @Override
    public void playgames(int gameName) {
        //todo 玩游戏
    }
}


iphone13pro(略)

定义工厂去生产他们

public class SimpleFactory {

    public static Iphone createIphone(String phoneName) {
        Iphone iphone = null;
        if ("Iphone13min".equals(phoneName)) {
            //todo 有自己的制造工艺,可能不是这么简单
            iphone = new Iphone13min();
        }
        if ("Iphone13".equals(phoneName)) {
            //todo 有自己的制造工艺,可能不是这么简单
            iphone = new Iphone13();
        }
        if ("Iphone13pro".equals(phoneName)) {
            //todo 有自己的制造工艺,可能不是这么简单
            iphone = new Iphone13pro();
        }
        //如果要加一个规格,在这里添加
        return iphone;
    }
}

测试


/**
 * 描述:测试简单静态工厂
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-15 6:01 下午
 */
public class TestSimpleFactory {
    
    public static void main(String[] args) {
        Iphone iphone13 = SimpleFactory.createIphone("Iphone13");
        System.out.println("生产的是 " + iphone13.getName());
        Iphone iphone13min = SimpleFactory.createIphone("Iphone13min");
        System.out.println("生产的是 " + iphone13min.getName());
    }
}

ps:这样的代码,对象的生产交由工厂完成,没有重复的new 语句。同时也满足,如果新增手机规格,调用方代码不需要更改。
结果:
在这里插入图片描述

工厂方法

什么叫“工厂方法”?多了“方法”两个字意味着什么?
简单工厂是:新建一个工厂类,由统一的工厂类生产不同规格的手机。但是如果有新的规格产生,我们就必须修改这个工厂类:

public class SimpleFactory {

    public static Iphone createIphone(String phoneName) {
        Iphone iphone = null;
        if ("Iphone13min".equals(phoneName)) {
            //todo 有自己的制造工艺,可能不是这么简单
            iphone = new Iphone13min();
        }
		if ("Iphone13pro".equals(phoneName)) {
		    //todo 有自己的制造工艺,可能不是这么简单
		    iphone = new Iphone13pro();
		}
		//如果要加一个规格,在这里添加
		if ("Iphone13proMax".equals(phoneName)) {
		    //todo 有自己的制造工艺,可能不是这么简单
		    iphone = new Iphone13proMax();
		}
	}
}

不同规格的手机在同一个工厂里面生产,如果新增一个规格,可能会影响其它规格的手机(代码中体现在,都在同一个类的方法中)。那么有没有办法解决这个问题呢?答案是有的,干脆不同的规格有不同的创建工厂,再抽出一个工厂接口类给调用者。
抽出的工厂接口:

/**
 * 描述:工厂方法接口
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-19 2:18 下午
 */
public interface MethodFactory {

    Iphone createIphone();
}

不同规格的工厂类实现:

/**
 * 描述:专门生产13的工厂
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-19 2:20 下午
 */
public class Iphone13Factory implements MethodFactory{
    @Override
    public Iphone createIphone() {
        //todo 实例化实际可能不是这么简单
        return new Iphone13();
    }
}
/**
 * 描述:专门生产13min的工厂
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-19 2:20 下午
 */
public class Iphone13minFactory implements MethodFactory{
    @Override
    public Iphone createIphone() {
        //todo 实例化实际可能不是这么简单
        return new Iphone13min();
    }
}

PS:工厂模式中核心工厂接口类不负责具体实例的创建,而是将具体的创建,交由对应规格的工厂类(实现核心工厂接口)去完成。

调用者调用:

public class TestMethodFactory {
    
    public static void main(String[] args) {
        //选择实际工厂
        MethodFactory iphone13Factory = new Iphone13Factory();
        //交由实际工厂实例化
        Iphone iphone13 = iphone13Factory.createIphone();
        //调用实例方法
        iphone13.getName();

        MethodFactory iphone13minFactory = new Iphone13minFactory();
        Iphone iphone13min = iphone13minFactory.createIphone();
        iphone13min.getName();

    }
}

其它

抽象的思想是为了抽出公共的东西,避免代码的重复。但实际上如果抽象层次过多,程序会变得异常复杂。
本来是想写抽象工厂模式的,但是发现很多文章,认为的是,我上面写的“工厂方法”就是抽象方法。大概是认为把工厂抽象了就是抽象工厂?闹不明白,再说了。

参考和注脚

工厂设计模式解决什么问题_使用工厂模式解决设计问题
JAVA设计模式之工厂模式—Factory Pattern


  1. 很多文章都提到了“客户端”这个概念,却没有哪里有过解释,也许是我孤陋寡闻了。以我多次遇见的理解,可以解释为实际“调用者”。熟悉分布式的同学,肯定了解服务提供者和消费者的概念。更细致地分,可以是方法提供者,方法调用者。所以我就用调用者来描述了。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值