工厂模式属于创建模式,包括简单工厂和抽象工厂。
简单工厂专门用来创建一类产品的产品类,由产品抽象类,产品类,工厂组成。调用者只根据抽象类进行调用,而具体的实例创建和规约则交给工厂去实现。其定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。(Define an interface for creating an object, but let subclass decide which class to instantiate.)
抽象工厂则是简单工厂的升级版,在有多个业务品种,业务分类时,抽象工厂提供统一的调用方式或接口,调用者只关心生产产品对象,而不用关心起实现类。其为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类。(Provide an interface for creating families of related or dependent objects without specifying their concrete classes.)
1. 工厂模式代码示例
public abstract class Books { //定义一个抽象的产品类
public abstract String getName();
public abstract String getAuthor();
public abstract int getPrice();
public abstract String getPublisher();
}
public class Book1 extends Books{ //其具体产品实现类,可以定义多个具体实现类
@Override
public String getName() {
// TODO Auto-generated method stub
return "日瓦格医生";
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "鲍里斯-帕斯捷尔纳克";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 39;
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "天津人名出版社";
}
}
public class Book2 extends Books{ //产品2
@Override
public String getName() {
// TODO Auto-generated method stub
return "平凡的世界";
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "路遥";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 89;
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "人民文艺出版社";
}
}
public abstract class abstractProductFactory { //定义个抽象的工厂类,可以用于产生多个工厂。提供给外部统一调用
public abstract <T extends Books> T createBook(Class<T> c); //此方法根据某个产品类的类名实例化该产品类
}
public class BooksFactory extends abstractProductFactory{ //具体工厂类,通过工厂实例化某类产品。
public BooksFactory() {
// TODO Auto-generated constructor stub
System.out.println("----------------------生产文学类书籍---------------------");
}
@Override
public <T extends Books> T createBook(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try {
book=(Books) Class.forName(c.getName()).newInstance();//在工厂中实现具体的产品类
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
}
abstractProductFactory BooksCreator=new BooksFactory(); //通过抽象工厂类调用。如果有多个工厂则可统一调用
//通过工厂生产两本书,调用者只需获得所要的产品对象,而不关心其怎么实现。
Books book=BooksCreator.createBook(Book1.class);//此处可以改为自己设定的选择条件来获得产品类
Books book2=BooksCreator.createBook(Book2.class);
System.out.println(book.getName()+"\t\t作者:"+book.getAuthor()+" 价格:"+book.getPrice()+" 出版商:"+book.getPublisher());
System.out.println(book2.getName()+"\t\t作者:"+book2.getAuthor()+" 价格:"+book2.getPrice()+" 出版商:"+book2.getPublisher());
----------------------生产文学类书籍---------------------
日瓦格医生 作者:鲍里斯-帕斯捷尔纳克 价格:39 出版商:天津人名出版社
平凡的世界 作者:路遥 价格:89 出版商:人民文艺出版社
2.抽象工厂代码示例
抽象工厂可以将类似的产品聚集成产品簇。例如我们将上面例子中的书划分为文学类的书和技术类的书两个不同的产品。而书又分为新出版和旧出版的书。抽象工厂可以有更多层次的划分,划分越多越复杂,其可读性则越低。但是他们都是基于书这个最高抽象。
public abstract class Books { //最高层抽象 书
public abstract String getName();
public abstract String getAuthor();
public abstract int getPrice();
public abstract String getPublisher();
public abstract String getPressDate();
}
public class Book1 extends Books{ //文学类的书的实现类, 此类书分为新和旧两个等级。
@Override
public String getName() {
// TODO Auto-generated method stub
return "日瓦格医生";
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "鲍里斯-帕斯捷尔纳克";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 39;
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "天津人名出版社";
}
@Override
public String getPressDate()
{
return "2017.3";
}
}
public class Book1Old extends Books{ //旧出版的书
@Override
public String getName() {
// TODO Auto-generated method stub
return "日瓦格医生";
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "鲍里斯-帕斯捷尔纳克";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 39;
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "天津人名出版社";
}
@Override
public String getPressDate()
{
return "2002.12";
}
}
public class book3 extends Books{ //技术类的书。新旧等级
@Override
public String getName() {
// TODO Auto-generated method stub
return "深入理解java虚拟机";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 28;
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "周志明";
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "机械工业出版社";
}
@Override
public String getPressDate() {
// TODO Auto-generated method stub
return "2016.6";
}
}
public class book3Old extends Books{ //旧书
@Override
public String getName() {
// TODO Auto-generated method stub
return "深入理解java虚拟机";
}
@Override
public int getPrice() {
// TODO Auto-generated method stub
return 28;
}
@Override
public String getAuthor() {
// TODO Auto-generated method stub
return "周志明";
}
@Override
public String getPublisher() {
// TODO Auto-generated method stub
return "机械工业出版社";
}
@Override
public String getPressDate() {
// TODO Auto-generated method stub
return "2006.6";
}
}
public abstract class abstractProduct { //工厂抽象类中,分别获得一本书的,新书实例类 和旧书实例
public abstract <T extends Books> T createBook(Class<T> c);
public abstract <T extends Books> T createOldBook(Class<T> c);
}
public class BooksFactory extends abstractProduct{ //生产文学类的书籍
public BooksFactory() {
// TODO Auto-generated constructor stub
System.out.println("----------------------生产文学类书籍---------------------");
}
@Override
public <T extends Books> T createBook(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try {
book=(Books) Class.forName(c.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
@Override
public <T extends Books> T createOldBook(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try { //此处通过给类名添加Old字符的方式 实现旧书类的实例化。 而调用者无须关心是怎么获取对象的。
book=(Books) Class.forName(c.getName()+"Old").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
}
public class BooksFactory2 extends abstractProduct{ //生产技术类的书籍的工厂。 此处还提供类静态的调用方法
//不同的工厂类生产不同类型的书籍 而不同类型的书籍可以有不同的初始化方法
@Override
public <T extends Books> T createBook(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try {
book=(Books) Class.forName(c.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
@Override
public <T extends Books> T createOldBook(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try {
book=(Books) Class.forName(c.getName()+"Old").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
public static<T extends Books> T createOldBook2(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
try {
book=(Books) Class.forName(c.getName()+"Old").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
//使用静态修饰 直接使用此类调用来实例产品。
public static <T extends Books> T createBook2(Class<T> c) {
// TODO Auto-generated method stub
Books book=null;
System.out.println("---------------------生产技术类书籍--------------------");
try {
book=(Books) Class.forName(c.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("书籍创建失败");
}
return (T) book;
}
}
//工厂方法测试
abstractProduct BooksCreator=new BooksFactory();
//此处通过抽象类工厂
Books book=BooksCreator.createBook(Book1.class);//此处可以将类名改为自己设定的选择条件
Books bookOld=BooksCreator.createOldBook(Book1.class); //调用者只关心获取旧书对象,而不关心怎么获取的。
System.out.println(book.getName()+"\t\t作者:"+book.getAuthor()+" 价格:"+book.getPrice()+" 出版商:"+book.getPublisher()+" 新书:"+book.getPressDate());
System.out.println(bookOld.getName()+"\t\t作者:"+bookOld.getAuthor()+" 价格:"+bookOld.getPrice()+" 出版商:"+bookOld.getPublisher()+" 旧书:"+bookOld.getPressDate());
//对工厂进行分类 不同的工厂生产不同种类的书籍 此处调用利用第二个工程生产技术类书籍。
/*
* 利用多工程生产不同类型的产品,可以使得创建工厂类职责清晰,而且结构简单。
* 但是给可扩展性和可维护性带来了一定的影响,如果要扩展一个产品类则要建立一个相应的工厂,从而增加了扩展难度。
* 维护时要考虑创建工厂类和产品类之间的关系。
* */
Books book3=BooksFactory2.createBook2(book3.class);
Books book3Old=BooksFactory2.createOldBook2(book3.class);
//此处直接通过静态的方式调用,存在更改风险。如果工厂的静态方法发生修改,则调用者也要发生修改。
System.out.println(book3.getName()+"\t\t作者:"+book3.getAuthor()+" 价格:"+book3.getPrice()+" 出版商:"+book3.getPublisher()+" 新书:"+book3.getPressDate());
System.out.println(book3Old.getName()+"\t\t作者:"+book3Old.getAuthor()+" 价格:"+book3Old.getPrice()+" 出版商:"+book3Old.getPublisher()+" 旧书:"+book3Old.getPressDate());
----------------------生产文学类书籍---------------------
日瓦格医生 作者:鲍里斯-帕斯捷尔纳克 价格:39 出版商:天津人名出版社 新书:2017.3
日瓦格医生 作者:鲍里斯-帕斯捷尔纳克 价格:39 出版商:天津人名出版社 旧书:2002.12
---------------------生产技术类书籍--------------------
深入理解java虚拟机 作者:周志明 价格:28 出版商:机械工业出版社 新书:2016.6
深入理解java虚拟机 作者:周志明 价格:28 出版商:机械工业出版社 旧书:2006.6
3. 工厂方法优缺点
优点:1 工厂方法具有良好的封装性,代码结构清晰。
2 一个对象创建是有条件约束的,如果一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建过程,降低了模块的耦合度。
3 可以通过扩充工厂类的方法,来增加产品类(横向扩展,在同一个产品簇中)。可以进行适应性扩展,而调用层面无须更改。
4 产品类的实现如何变化,调用者无须关心,调用者只与高层抽象或接口有关,只要接口不变上层调用就不会发生改变,降低了增加或减少产品类带来的修改风险。
缺点:1 产品簇扩展非常困难(纵向扩展),如果要增加一类产品则要从工厂的抽象到工厂实现都要发生更改,而更改抽象则其调用处也要发生更改,从而将修改风险扩散到其他模块。