4、工厂方法模式、简单工厂、多方法静态工厂(常用)工厂模式 创造型模式
1、简单工厂模式
2、多方法静态工厂
3、工厂方法模式
4、抽象工厂模式
先带大家伙入个门~ 从简单工厂和多方法静态工厂入门~~
1、简单工厂模式
简单工厂:通过实例化一个工厂类,来获取对应的产品实例。我们不需要关注产品本身如何被创建的细节,只需要通过相应的工厂就可以获得相应的实例。简单工厂包括三种角色:
1.工厂:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
2.抽象产品 :简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
3.具体产品:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
实例:
1.1定义一个Drinks
Drinks作为产品的抽象类并且有抽象方法produce();(抽象产品)
package cn.design.factorymethod.simplefactory;
/**
* @author lin
* @version 1.0
* @date 2020-07-16 16:53
* @Description Drinks作为产品的抽象类并且有抽象方法produce();(抽象产品)
*/
public abstract class Drinks {
protected abstract void produce();
}
1.2定义一个Sprite
2.Sprite继承Drinks是要被具体生产出来的产品,他重写了produce()方法。(具体产品)
package cn.design.factorymethod.simplefactory;
/**
* @author lin
* @version 1.0
* @date 2020-07-16 16:53
* @Description 2.Sprite继承Drinks是要被具体生产出来的产品,他重写了produce()方法。(具体产品)
*/
public class Sprite extends Drinks {
1.3定义一个Cola
3.Cola同样也继承了Drinks,是要被生产出来的具体产品。
package cn.design.factorymethod.simplefactory;
/**
* @author lin
* @version 1.0
* @date 2020-07-16 16:56
* @Description 3.Cola同样也继承了Drinks,是要被生产出来的具体产品。
*/
public class Cola extends Drinks {
1.4定义一个DrinksFactory
4.DrinksFactory为简单工厂,向外暴露produceDrink方法来获取产品的实例(工厂)
package cn.design.factorymethod.simplefactory;
/**
* @author lin
* @version 1.0
* @date 2020-07-16 16:57
* @Description 4.DrinksFactory为简单工厂,向外暴露produceDrink方法来获取产品的实例(工厂)
*/
public class DrinksFactory {
public Drinks produceDrink(Class className) {
try {
return (Drinks) Class.forName(className.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
1.5定义测试类
package cn.design.factorymethod.simplefactory; /** * @author lin * @version 1.0 * @date 2020-07-16 18:20 * @Description 5.Client为应用层,Client端想要获取到Cola或者Sprite对象,只要通过DrinkFactory中的produceDrink方法传入相对应的对应的产品 */ public class Client { public static void main(String[] args) { DrinksFactory factory = new DrinksFactory(); Cola cola = (Cola) factory.produceDrink(Cola.class); cola.produce(); Drinks sprite = factory.produceDrink(Sprite.class); sprite.produce(); } }
运行结果如下:
Drink Cola drink sprite
1.6优缺点
简单工厂的优点: 1.不需要关心类的创建细节。 2.减轻类之间的耦合依赖,具体类的实现只是依赖于简单工厂,而不依赖其他类。 简单工厂的缺点: 1.扩展复杂,当简单工厂需要生产出另外一种产品的时候,需要扩展工厂的内部创建逻辑,比较有可能引起较大的故障 2.由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中
2、多方法静态工厂
我们知道,上面的简单工厂模式有一个缺点是不同的产品需要不同的额外参数的时候,是不支持的,
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。
而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
请看下面的例子。
定义一个StaticDrinksFactory
package cn.design.factorymethod.simplefactory; /** * @author lin * @version 1.0 * @date 2020-07-16 18:57 * @Description TODO */ public class StaticDrinksFactory { public static Drinks createCola() { return new Cola(); } public static Drinks createSprite() { return new Sprite(); } }
定义一个测试类
package cn.design.factorymethod.simplefactory; /** * @author lin * @version 1.0 * @date 2020-07-16 18:20 * @Description 5.Client为应用层,Client端想要获取到Cola或者Sprite对象,只要通过DrinkFactory中的produceDrink方法传入相对应的对应的产品 */ public class Client2 { public static void main(String[] args) { Drinks cola = StaticDrinksFactory.createCola(); cola.produce(); Drinks sprite = StaticDrinksFactory.createSprite(); sprite.produce(); } }
运行结果如下:
Drink Cola drink sprite
3、工厂方法模式
在Factory Method模式中,父类决定实例的生成方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责。这样就可以将生成实例的框架(framework)和实际负责生成实例的类解耦。
实例:
类的功能一览表:
Product 只定义抽象方法use的抽象类 Factory 实现了create方法的抽象类 IDCard 实现了use方法的类 IDCardFactory 实现了createProduct、registerProduct方法的类 EmailCard 实现了use方法的类 EmailCardFactory 实现了createProduct、registerProduct方法的类 Main 测试程序行为的类
3.1定义Product类
package cn.design.factorymethod.framework; /** * @author lin * @version 1.0 * @date 2020-07-16 15:53 * @Description TODO */ public abstract class Product { public abstract void use(); }
3.2定义Factory类
package cn.design.factorymethod.framework; /** * @author lin * @version 1.0 * @date 2020-07-16 15:55 * @Description TODO */ public abstract class Factory { public final Product create(String owner) { Product product = createProduct(owner); registerProduct(product); return product; } protected abstract Product createProduct(String owner); protected abstract void registerProduct(Product product); }
3.3定义IDCard类
package cn.design.factorymethod.idcard; import cn.design.factorymethod.framework.Product; /** * @author lin * @version 1.0 * @date 2020-07-16 16:00 * @Description TODO */ public class IDCard extends Product { private String owner; public IDCard(String owner) { this.owner = owner; System.out.println("制作" + owner + "的ID卡"); } @Override public void use() { System.out.println("使用" + owner + "的ID卡"); } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
3.4定义IDCardFactory类
package cn.design.factorymethod.idcard; import cn.design.factorymethod.framework.Factory; import cn.design.factorymethod.framework.Product; import java.util.ArrayList; import java.util.List; /** * @author lin * @version 1.0 * @date 2020-07-16 16:02 * @Description TODO */ public class IDCardFactory extends Factory { private List<String> owners = new ArrayList<>(); @Override protected Product createProduct(String owner) { return new IDCard(owner); } @Override protected void registerProduct(Product product) { owners.add(((IDCard) product).getOwner()); } public List<String> getOwners() { return owners; } }
3.5定义EmailCard类
package cn.design.factorymethod.idcard; import cn.design.factorymethod.framework.Product; /** * @author lin * @version 1.0 * @date 2020-07-16 16:00 * @Description TODO */ public class EmailCard extends Product { private String email; public EmailCard(String owner) { this.email = owner; System.out.println("制作email卡:" + owner); } @Override public void use() { System.out.println("使用email卡:" + email); } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
3.6定义EmailCardFactory类
package cn.design.factorymethod.idcard; import cn.design.factorymethod.framework.Factory; import cn.design.factorymethod.framework.Product; import java.util.ArrayList; import java.util.List; /** * @author lin * @version 1.0 * @date 2020-07-16 16:02 * @Description TODO */ public class EmailCardFactory extends Factory { private List<String> emails = new ArrayList<>(); @Override protected Product createProduct(String email) { return new EmailCard(email); } @Override protected void registerProduct(Product product) { emails.add(((EmailCard) product).getEmail()); } public List<String> getEmails() { return emails; } }
3.7定义Main测试类
package cn.design.factorymethod; import cn.design.factorymethod.framework.Factory; import cn.design.factorymethod.framework.Product; import cn.design.factorymethod.idcard.EmailCardFactory; import cn.design.factorymethod.idcard.IDCardFactory; import com.sun.org.apache.bcel.internal.generic.NEW; /** * @author lin * @version 1.0 * @date 2020-07-16 15:43 * @Description TODO */ public class TestMain { public static void main(String[] args) { Factory factory=new IDCardFactory(); Product p1 = factory.create("小明"); p1.use(); EmailCardFactory factory2 = new EmailCardFactory(); Product p2 = factory2.create("123@qq.com"); p2.use(); } }
运行结果如下:
制作小明的ID卡 使用小明的ID卡 制作email卡:123@qq.com 使用email卡:123@qq.com
优点
更符合开-闭原则 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
简单工厂模式需要修改工厂类的判断逻辑
符合单一职责原则 每个具体工厂类只负责创建对应的产品
简单工厂中的工厂类存在复杂的switch逻辑判断
不使用静态工厂方法,可以形成基于继承的等级结构。
简单工厂模式的工厂类使用静态工厂方法
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
缺点
添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类; 一个具体工厂只能创建一种具体产品
应用场景
在了解了优缺点后,我总结了工厂方法模式的应用场景:
当一个类不知道它所需要的对象的类时 在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可; 当一个类希望通过其子类来指定创建对象时 在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
这是一个稍偏基础和偏技术的公众号,甚至其中包括一些可能阅读量很低的包含代码的技术文,不知道你是不是喜欢,期待你的关注。
代码分享
微信公众号 点击关于我,加入QQ群,即可获取到代码以及高级进阶视频和电子书!!
如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~
● 扫码关注我们
据说看到好文章不推荐的人,服务器容易宕机!
本文版权归 发哥讲 和 博客园 共有,原创文章,未经允许不得转载,否则保留追究法律责任的权利。