Java设计模式之工厂方法模式

工厂方法模式共分为三种:普通工厂模式,静态工厂模式,抽象工厂模式

1、普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。首先请看下关系图。
Java普通工厂设计模式

举例如下:(我们举一个发送邮件和短信的例子)
首先,创建二者的共同接口:

//1.首先写一个接口
public interface Sender {
    //不用加abstract关键字,在这里默认就是抽象方法
    public void send();
}
//2.1紧接着创建两个实现接口1
public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("send sms");
    }
}
//2.2紧接着创建两个实现接口2
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("send mail");
    }
}
//3.创建工厂类
public class SendFactory {

    //生产方法生产产品,由于还不知道生产的是什么产品,所有用大的父类Sender来接收
    //到底生产的产品是什么由传入的参数决定
    public Sender produce(String name){
        if("sms".equals(name)){
            return new SmsSender();
        }else if("mail".equals(name)){
            return new MailSender();
        }else{
            System.out.println("无法生产此产品");
            return null;
        }
    }

}
//创建测试类
public class TestFactoryDemo {
    public static void main(String[] args) {
        //1.通过工厂来创建对象
        SendFactory sf = new SendFactory();
        //2.调用工厂的生产方法,生产对象
        Sender s = sf.produce("sms"); //此方法返回的是Sender的一个子类
        s.send(); //调用父类的方法,如果子类重写了父类的方法,父类的引用只能调用子类重写的方法(多态)
        //也就是说上面传入的哪个子类的参数我们就调用哪个子类的方法  
    }
}

/

2、静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
如果向调用的工厂方法中随意的传值的话,可能会造成空指针异常,那么怎么处理呢?

//修改完善TestFactoryDemo,避免用户随意输入造成的空指针异常
public class TestFactoryDemo {
    public static void main(String[] args) {
        //1.通过工厂来创建对象
//      SendFactory sf = new SendFactory();
        //2.调用工厂的生产方法,生产对象
//      Sender s = sf.produce();
//      s.send();

        //完善工厂类,使其避免null指针(设计的结构上)
        //在工厂类中分别给不同的产品创建不同的方法,不让用户输入
        //为了可以使用SendFactory直接调用方法,我们可以将SendFactory中的方法加static直接提升为静态方法
        Sender sms = SendFactory.produceSms();
        sms.send();

    }
}
//修改SendFactory类,不让用户输入
//将一个方法拆成两个方法,这时在TestFactoryDemo类中用户想创建哪个调用哪个方法就不会报错了.
public class SendFactory {

    //生产产品
    /*public Sender produce(String name){
        if("sms".equals(name)){
            return new SmsSender();
        }else if("mail".equals(name)){
            return new MailSender();
        }else{
            System.out.println("无法生产此产品");
            return null;
        }
    }*/
    //加static提升为静态方法,方便直接使用类名.调用静态方法
    public static Sender produceMail(){
        return new MailSender();
    }

    public static Sender produceSms(){
        return new SmsSender();
    }

}

3、抽象工厂模式(Abstract Factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则(即:对扩展开发,对修改关闭。在程序的需求发生变化的时候,不能去修改源代码,而是去扩展新的功能模块,实现热插拔的效果。),所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。

抽象工厂模式

//创建一个接口,强制要求每个工厂都具有生产能力
public interface Provider {
    //规范,要求工厂都具备的生产能力
    //Sender是所有产品的父类
    public Sender produce();

}
//实现Provider接口
public class MailSenderFactory implements Provider {
    @Override
    public Sender produce() {
        return  new MailSender();
    }
}
//实现Provider接口
public class SmsSenderFactory implements Provider {
    @Override
    public Sender produce() {
        return new SmsSender();
    }
}
//调用对象
import java.util.ResourceBundle;

public class TestFactoryDemo {
    public static void main(String[] args) throws Exception {

        //资源句柄,读取java配置文件中的资源数据的
        ResourceBundle rb = ResourceBundle.getBundle("xxx.xxx.finallyfactory.config");//读取配置文件的方式
        String str = rb.getString("factoryInfo");
        System.out.println(str);
        //1.创建工厂对象  
        Class factoryClass = Class.forName(str);//反射的方式
        Provider factory = (Provider) factoryClass.newInstance();
        //2.生产产品
        Sender sender = factory.produce();
        sender.send();

    }
}
//配置文件资源
//config.properties
factoryInfo=xdl.day23.finallyfactory.SmsSenderFactory

工厂设计模式总结
工厂接口
具体的工厂1
具体的工厂2
商品接口
具体的商品接口1
具体的商品接口2
测试类
创建具体的工厂对象
使用工厂对象创建商品对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值