设计模式~简单工厂模式
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
工厂模式专门负责将大量有共同接口的类实例化。
工厂模式的几种形态:
- 简单工厂模式(Simple Factory):又称静态工厂方法模式
- 工厂方法模式(Factory Method):又称多态性工厂模式或虚拟构造子模式
- 抽象工厂模式(Abstract Factory): 又称工具箱模式
简单工厂模式的结构
从上图可以看出,简单工厂模式涉及到工厂角色、抽象产品角色以及具体产品角色等三个角色:
- 工厂类角色(Creator): 担任这个角色的是工厂方法模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体的java类实现。
- 抽象产品角色(Product): 担任这个角色的类是由工厂方法模式所创建的对象的父类,或他们共同拥有的接口。抽象产品角色可以用一个java接口或者java抽象类实现。
- 具体产品角色(Concrete Product): 工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体java类实现。
工厂类的示意性源代码:
Creator类的源代码:
public class Creator {
public static Product factory(){
return new ConcreteProduct();
}
}
抽象角色Product接口的源代码:
public interface Product {
}
具体角色ConcreteProduct类的源代码:
public class ConcreteProduct implements Product {
public ConcreteProduct(){}
}
简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一种产品类的实例。
简单工厂模式的优点和缺点
优点:
模式的核心是工厂类。这个类含有必要的判断逻辑,可以决定在什么时候创建哪个产品类的实例。
而客户端则可以免除直接创建产品对象的责任,而仅仅负责消费产品。
简单工厂模式通过这种做法实现了对责任的分割。
缺点:
当产品类有负责的多层等级结构时,工厂类只有它自己。以不变应万变,就是模式的缺点。
这个工厂类集中了所有产品的创建逻辑,形成一个无所不知的全能类。它需要对所有的产品负责,如果它一旦不能工作,使用到这些产品的地方就都不能工作了。
另一个缺点,当产品类有不同的接口种类时,工厂类需要判断在什么时候创建某种产品。这种对时机的判断和对哪一种具体产品的判断逻辑混合在一起,使得系统在将来进行功能扩展时较为困难。这一缺点在工厂方法模式中得到克服。
再者,由于简单工厂模式使用静态方法作为工厂方法,而静态方法无法由子类继承,因此,工厂角色无法形成基于继承的等级结构。这一缺点会在工厂方法中得到克服。
总结一下就是三个缺点:
- 会造成程序对该工厂类的强依赖,一旦工厂类出现问题,整个程序都受影响。
- 当工厂类有不同接口种类时,将来进行功能扩展会变的困难。
- 工厂角色无法形成继承的等级结构。
简单工厂模式在java中的应用
DateFormat与简单工厂模式
示例
接口 Fruit的源码
public interface Fruit {
/**
* 生长
*/
void grow();
/**
* 收获
*/
void harvest();
/**
* 种植
*/
void plant();
}
Apple类的源代码
public class Apple implements Fruit {
private int treeAge;
@Override
public void grow() {
// TODO Auto-generated method stub
log("Apple is growing...");
}
@Override
public void harvest() {
// TODO Auto-generated method stub
log("Apple has been harvested.");
}
@Override
public void plant() {
// TODO Auto-generated method stub
log("Apple has been planted.");
}
/**
* 辅助方法
* @param msg
*/
public static void log(String msg){
System.out.println(msg);
}
/**
* 树龄的取值方法
* @return
*/
public int getTreeAge(){
return treeAge;
}
/**
* 树龄的赋值方法
* @param treeAge
*/
public void set(int treeAge){
this.treeAge = treeAge;
}
}
Grape类的源代码
public class Grape implements Fruit {
private boolean seedless;
@Override
public void grow() {
// TODO Auto-generated method stub
log("Grape is growing...");
}
@Override
public void harvest() {
// TODO Auto-generated method stub
log("Grape has been harvested.");
}
@Override
public void plant() {
// TODO Auto-generated method stub
log("Grape has been planted.");
}
public static void log(String msg){
System.out.println(msg);
}
public boolean getSeedless(){
return seedless;
}
public void setSeedless(boolean seedless){
this.seedless = seedless;
}
}
Strawberry的源代码
public class Strawberry implements Fruit {
@Override
public void grow() {
// TODO Auto-generated method stub
log("Strawberry is growing...");
}
@Override
public void harvest() {
// TODO Auto-generated method stub
log("Strawberry has been harvested.");
}
@Override
public void plant() {
// TODO Auto-generated method stub
log("Strawberry has been planted.");
}
public static void log(String msg){
System.out.println(msg);
}
}
FruitGardener类的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class FruitGardener { public static Fruit factory(String which) throws BadFruitException{ if (which.equalsIgnoreCase( "apple" )){ return new Apple(); } else if (which.equalsIgnoreCase( "strawberry" )){ return new Strawberry(); } else if (which.equalsIgnoreCase( "grape" )){ return new Grape(); } else { throw new BadFruitException( "Bad fruit request" ); } } } |
BadFruitException类的源代码
1 2 3 4 5 6 | public class BadFruitException extends Exception { public BadFruitException(String msg){ super (msg); } } |
怎么使用BadFruitException
public class SimpleFactoryClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
FruitGardener.factory("grape");
FruitGardener.factory("apple");
FruitGardener.factory("strawberry");
}catch(BadFruitException e){
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2019-07-27 微服务之初了解(一)