java-設計模式-工場方法
2024-09-08 09:58:22
工廠方法:
一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。
这满足创建型模式中所要求的“创建与使用相分离”的特点。
解析:
被创建的对象称为“产品”
把创建产品的对象称为“工厂”
優點:
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程; 增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
模式結構
抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法
newProduct() 来创建产品。
具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
適用場景
编写代码的过程中, 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。
将创建产品的代码与实际使用产品的代码分离, 从而能在不影响其他代码的情况下扩展产品创建部分代码。
希望用户能扩展你软件库或框架的内部组件, 可使用工厂方法。
問題:
继承可能是扩展软件库或框架默认行为的最简单方法。 但是当你使用子类替代标准组件时, 框架如何辨识出该子类? 解决方案是将各框架中构造组件的代码集中到单个工厂方法中, 并在继承该组件之外允许任何人对该方法进行重写。
复用现有对象来节省系统资源, 而不是每次都重新创建对象, 可使用工厂方法
實現方法
让所有产品都遵循同一接口。 该接口必须声明对所有产品都有意义的方法。 在创建类中添加一个空的工厂方法。 该方法的返回类型必须遵循通用的产品接口。 在創建者即抽象工廠中對抽象產品的構造函數做出引用。 為每一種產品編寫一個創建者子類。子类中重写工厂方法, 并将基本方法中的相关创建代码移动到工厂方法中。
簡單例子
/**
* 抽象接口:提供產品的接口
*/
public interface Product {
public void show();
}
/**
* 提供產品的抽象工廠
*/
public interface AbstractProductFactory {
public Product newProduct();
}
/**
* 具體產品:實現抽象產品接口
*/
public class ConcreteProduct1 implements Product{
public void show() {
System.out.println("具體產品1展示");
}
}
/**
* 具體工廠:實現抽象工廠裏的方法。
*/
public class ConcreteProductFactory1 implements AbstractProductFactory { public Product newProduct() {
System.out.println("具體工廠11---->具體產品2");
return new ConcreteProduct1();
}
}
public class FactoryTest {
public static void main(String[] args) {
/**
* 使用具體工程創建具體產品就行
*/
AbstractProductFactory cf = new ConcreteProductFactory1();
Product product1 = cf.newProduct();
product1.show();
/**
* re:
* 具體工廠11---->具體產品2
* 具體產品1展示
*/
}
}
便於理解的生活例子
正在开发一款物流管理应用。 最初版本只能处理卡车运输, 因此大部分代码都在位于名为 卡车
的类中。
現在希望希望应用能够支持海上物流功能。
因爲大部分代码都与 卡车
类相关。程序中添加 轮船
类需要修改全部代码
解決方法:
工厂方法模式建议使用特殊的工厂方法代替对于对象构造函数的直接调用 (即使用 new
运算符)。
对象仍将通过 new
运算符创建, 只是该运算符改在工厂方法中调用罢了。
工厂方法返回的对象通常被称作 “产品”。
可能大家有疑問:
我们只是改变了程序中调用构造函数的位置而已。
事實上
现在你可以在子类中重写工厂方法, 从而改变其创建产品的类型。
注意:
仅当这些产品具有共同的基类或者接口时, 子类才能返回不同类型的产品,
同时基类中的工厂方法还应将其返回类型声明为这一共有接口
最新文章
- ember.js:使用笔记4 数组数据的分组显示
- html5之canvas初解
- 文字处理控件TX Text Control X10独家揭秘(一):数据源自动处理
- css:map热点的应用
- ado通用操作数据单元
- C#_事件委托
- cocos2dx之lua项目开发中MVC框架的简单应用
- U3D操作游戏对象
- Redis的过期策略和内存淘汰策略(转)
- T研究:国内云BPM市场规模尚小,预计2018年仅为3.29亿元
- day 3 - 2 数据类型练习
- (转)为什么wait(),notify()和notifyAll()必须在同步块或同步方法中调用
- Arraylist集合遍历输出
- keepalive的工作原理和如何做到健康检查
- motor的使用
- iOS CrashLog Analysis
- pbft流程深层分析和解释(转)
- flask在其他文件中添加路由
- 基于SVG+AJAX的网页数据监控
- C语言复习---获取最大公约数(辗转相除法和更相减损法)
热门文章
- python-xlutils模块-修改excel
- ASP.NET Core 6框架揭秘实例演示[11]:诊断跟踪的几种基本编程方式
- 如何制作报表?报表教程:适合你的热销车TOP25
- System.Console.WriteLine() 调用原理
- AndroidMainifest.xml文件属性
- 02-asio学习
- JZ-069-在 O(1) 时间内删除链表节点
- Linux CentOS7.X- 添加用户
- Xmake 和 C/C++ 包管理
- Python安装包报错:PackagesNotFoundError: The following packages are not available from current channels