Java设计模式:四、工厂模式

工厂模式


也许有一些地方写的不够明确,如有错误,请各位大神指出。下面是从HeadFirst设计模式学习中,做的笔记:

HeadFirst设计模式工厂模式笔记

一、简单工厂模式

传统的生成对象方式为new形式,如果一个接口有多个不同的实现类,根据不同的类型new不同的对象,常见的形式为if语句或switch语句来new对象。比如:推送微信消息,有一个抽象的实体类:SendMsg,其中有一个抽象方法为sendMsg()。给微信推送消息,可以推送模板消息,也可以推送图文消息。暂时有这两个子类。所以,类的基本形式如下:

public abstract class SendMsg {
    public abstract void sendMsg();
    //other method...
}
public class SendTempMsg extends SendMsg {
    public void sendMsg(){
        //发送模板消息代码
    }
}
public class SendCustomerMsg extends SendMsg {
    public void sendMsg(){
        //推送图文消息代码
    }
}

上面是对实现类的一个定义。如果要使用,传统方式如下:

public class Test {
    public static void main(String[] args){
        int type = 1;
        SendMsg sendMsg;
        switch (type) {
            case: 1
                sendMsg = new SendTempMsg();
                break;
            case: 2
                sendMsg = new SendCustomerMsg();
                break;
        }
        sendMsg.sendMsg();
    }
}

简单工厂模式,基本是将new这一部分代码移动到了一个工厂类中。下面定义工厂类:

public class SendMsgFactory {
	public static SendMsg createSendMsg(int type) {
		SendMsg sendMsg;
		switch (type) {
			case: 1
				sendMsg = new SendTempMsg();
			case: 2
				sendMsg = new SendCustomerMsg();
			defaults:
				throw new IllegalArguments("不支持创建其他类型");
		}
		return sendMsg;
	}
}

使用类:

public class Test {
	public static void main(String[] args) {
		SendMsg sendMsg = SendMsgFactory.createSendMsg(1);
		sendMsg.sendMsg();
	}
}

上面形式便是简单工厂模式。好像简单工厂和传统方式并没有什么区别,只是把一部分代码移动到了一个单独的类中。但是,使用简单工厂方法模式以后,会发现,使用者完全不知道内部是如何实现的。只知道通过工厂可以创建一个推送消息的类。所以如果后期对子类进行增加或者删除时,使用者完全不知道。但是如果使用传统形式,使用者一看便知道,有两个推送消息的类,而且紧密的与这些类耦合在了一起,假如有一天不需要其中一个了,把它移除了,使用者也必须去把它移除。这样耦合度就比较高了。

二、工厂方法模式

定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法的目的是将类的实例化推迟到子类。

大致类图如下:


温习工厂模式,是由于目前手上正好有一个任务,可以使用到工厂模式,所以借此机会,再熟悉熟悉工厂模式。

任务的背景大概是:

将称重商品的称重码导出为数据格式为指定格式的txt文件。目前的任务只支持导出一种格式,即DHTMA07格式。(格式为数据格式,不是导出后文件的格式,比如导出xml形式的txt文件,比如导出json形式的txt文件。为了方便,下面的例子以xml格式和json格式来举例。)

使用传统的方式实现:

public class PluFile {
	public PluData buildJsonPluData(){
		//...封装格式为json形式的数据
	}

	public PluData buildXmlPluData(){
		//...封装格式为xml形式的数据
	}

	public void buildFile(PluData data){
		//...将封装好的格式数据写入到一个本地文件中
	}
}

public class PluFileTest {
	public static void main(String[] args) {
		PluFile pluFile = new PluFile();
		PluData pluData = new PluData();
		String type = "json";
		switch (type) {
			case "json":
				pluData = pluFile.buildJsonPluData();
			case "xml":
				pluData = pluFile.buildXmlPluData();
			default:
				throw new IllegalArgumentsException("不支持的格式");
		}
		pluFile.buildFile(pluData);
	}
}

上面是不适用工厂方法模式,测试类相当于客户端。PluFile直接暴露了其内部实现。这种方式是不容易扩展的。根据Effective Java中提到的,使类和成员的可访问性最小化,一旦类的成员暴露在外边,被多个地方调用,后期如有修改,将会变得很麻烦。而且客户端需要时时去关心它的内部实现。比如现在的新增了一个需求,导出格式为properties形式的txt文件。在服务端不仅要新增新建properties形式的,在客户端还要新增case语句。所以,这种方式虽然能实现功能,但并不是最好的实现方式。如果使用工厂方法模式:

/**
 * 产品类。让具体的产品继承它,实现对应的格式
 **/
public abstract class PluFile {
	public abstract PluData buildData();

	public void buildFile(PulData pluData) {
		//将对应的格式写入到本地txt文件中
	}
}

public class JsonPluFile extends PluFile{
	public PluData buildData (){
		//封装格式为json的格式
	}
}

public class XmlPluFile extends PluFile {
	public PluData buildData (){
		//封装格式为xml的格式
	}
}

/**
 * 产品创建工厂。具体的产品,到具体的工厂类下创建,写成抽象类的原因是,可以将产品的一系列相同的操作放在一起。
 **/
public abstract class PluFileFactory {

	public abstract PluFile createPluFile();

	public static PluFileFactory createFactoryByType(String type) {
    	switch (type) {
      		case "json":
        		return new JSONPluFileFactory();
        	case "xml":
        		return new XMLPluFileFactory();
      	default:
        throw new IllegalArgumentException("不支持创建的格式");
    	}
  	}

  	public void createPluFileAndTotxt(List<ShopSku> shopSkuList) throws IOException, ShopSkuException {
    	PluFile pluFile = createPluFile();
    	pluFile.buildFile(pluFile.buildData());
  }
}

/**
 * 创建JSON形式的产品
 **/
public class JsonPluFileFactory extends PluFileFactory {
	public PluFile createPluFile (){
		return new JsonPluFile();
	}
}

/**
 * 创建XML形式的产品
 **/
public class XmlPluFileFactory extends XmlFileFactory {
	public PluFile createPluFile (){
		return new XmlPluFile();
	}
}
public class PluFileTest {
	public static void main(String[] args) {
		String type = "json";
		PluFileFactory.createFactoryByType(type).createPluFileAndTotxt();
	}
}

使用工厂方法模式,它的好处是容易扩展。而且客户端并不知道其内部实现,如果后期扩展格式,客户端也不用关心具体如何实现,只要传入一个对应的格式,得到对应的结果即可。


三、抽象工厂模式




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值