之前在《设计模式之Template Method模式》一文中详细讲了Template Method的思想,今天我们来讲一片跟这种模式看上去很相似,但是却完全不同的一个设计模式Factory Method模式。
还是先说说这种模式的思想,这种模式注重“框架”二字,主要思想就是通过抽象类创建需要的实例,然后具体怎么创建交给子类去决定。还是用一个需求来作为例子说明。现在有这么个需求,我想要定义一个工厂,用于生产简单版的身份证。
就是这么简单的一个需求,现在我们来分析一下这个需求。首先身份证是由国家部门严格把控的,所以这个身份证肯定会跟主人一一对应,并且得注册。具体一张身份证给那个人用,这是由政府部门决定,工厂只是负责生产身份证,在生产的时候就根据政府部门的要求,将编号给固定了。好了,大体的思路现在有了,首先得有一个IDCardFartory类,用于生产IDCard,并且对政府部门提供注册的API。然后还得有一个IDCard类。用于存储IDCard的信息,还得有一个Person类,用于对应IDCard。因为上面讲到了这篇文章讲的是Factory Method模式,还是注重“框架”二字的。那我们肯定得搭建一个固定生产模式的框架出来,上面讲到的这几个类都是具体去实现细节的类,我们设计模式讲究的是一种面向接口,面向抽象的开发模式,所以这儿我们得有两个抽象的基类,用于固定一种模式。首先得有一个产品类Product,用于决定该产品的一些基本信息模式。再接着得有一个工厂Factory类,用于决定这种类型的工厂的行为模式。看具体的实现:
因为上面说到了,Product类和Factory类是用于决定一种生产模式的“框架的”,那我们把他们都放在同一个包framework包中,Product类,是产品的基类,肯定有一个方法,使用use方法,让用户去使用产品,还得提供一个设置主人的方法,以后这个产品跟人得一一对应。那就必须设定该方法,让相关部门去设定主人。
/** * Created by PICO-USER on 2017/3/10. */ public abstract class Product { public abstract void use(); public abstract void setOwner(Person owner); }
有了产品的基类,我们还差一个工厂的基类Factory,这个工厂类规定了一种模式的工厂,工厂用于生产产品,那肯定有一个createProduct方法,还得提供祖册方法,让相关部门去注册该产品,后面我们想能够拿到该工厂生产的产品都是那些人在用,并且是谁在用哪一个产品,那我们需要一个集合用来存储这些数据,相关部门能查证。
/** * Created by PICO-USER Dragon on 2017/3/10. */ public abstract class Factory { public Product create() { Product product = createProduct(); return product; } protected abstract Product createProduct(); public abstract void registerProduct(Product product); public abstract Map<Long, Person> getSerials(); }框架有了,那接下来就是具体的实现了,还是先来实现产品方面的具体细节,在本例中产品就是IDCard,该类继承了Product类,具有Product类规定的特有方法,还拓展了一些特殊功能,在本例中按理说,产品都应该有产品号,所以cardNumber应该在父类中就有的,但是这儿没有放到分类中,要放到父类中也行。但是这儿我不想在基类中添加变量,故而放到子类中了。
/** * Created by PICO-USER on 2017/3/10. */ public class IDCard extends Product { private long cardNumber; private Person owner; IDCard(long cardNumber) { this.cardNumber = cardNumber; } public long getCardNumber() { return cardNumber; } public void setCardNumber(long cardNumber) { this.cardNumber = cardNumber; } public Person getOwner() { return owner; } @Override public void use() { System.out.print(owner.getName() + " is using card ,the cardNumber is " + cardNumber + "\n"); } @Override public void setOwner(Person owner) { this.owner = owner; } }
产品这边的具体有了,接下来就是工厂的具体实现,该类继承Factory基类,实现createProduct方法用于具体生产产品,该方法是受保护的,在Main类中,因为跟该类不在同一个包,所以无法调用该方法,还有IDCard的构造方法是没有public修饰的,Main类中也不能通过new得到IDCard的对象。强制要求Main类只能通过Factory的create方法得到。registerProduct方法,getSerials方法却是public,这儿为什么要是public修饰呢?因为注册功能,和查询功能应该都是政府部门进行,所以需要对外暴露出来,让Main类中可以调用。
/** * Created by PICO-USER Dragon on 2017/3/10. */ public class IDCardFactory extends Factory { Map<Long, Person> serials = new HashMap<>(); private long cardNumber = 1000; @Override protected synchronized Product createProduct() { System.out.print("produce the card , number is " + cardNumber + "\n"); IDCard idCard = new IDCard(cardNumber); cardNumber++; return idCard; } @Override public void registerProduct(Product product) { IDCard idCard = (IDCard) product; serials.put(idCard.getCardNumber(), idCard.getOwner()); } @Override public Map<Long, Person> getSerials() { return serials; } }
再来看看Main类的代码,这是用于测试用的类。不多说了。
public class Main { public static void main(String[] args0) { Factory cardFactory = new IDCardFactory(); Product card1 = cardFactory.create(); card1.setOwner(new Person("A", 18, "girl")); cardFactory.registerProduct(card1); Product card2 = cardFactory.create(); card2.setOwner(new Person("B", 20, "boy")); cardFactory.registerProduct(card2); card1.use(); card2.use(); Map<Long, Person> serials = cardFactory.getSerials(); for (Map.Entry<Long, Person> entry : serials.entrySet()) { Long key = entry.getKey(); Person value = entry.getValue(); System.out.print("number :" + key + " owner :" + value.toString() + "\n"); } } }
Factory Method 模式在这儿就讲完了,在这儿再总结一下该模式。上面已经说得很清楚了,该模式侧重的是一种“框架”式的开发,用于规范项目的整体风格。可以跟Template Method模式对照学习。