这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战 @TOC
简单工厂模式
传统方式
- 通过一个传统的项目来介绍工厂模式:看一个包子的项目:要便于包子种类的扩展,要便于维护,需求如下:
- 包子的种类很多 比如肉包子,菜包子等
- 包子的制作有 prepare,baopi, fangruxianliao, cooking
- 完成包子店订购功能。
- 代码如下:
- 包子铺
public class baoziStore {
public static void main(String[] args) {
// TODO 自动生成的方法存根
new OrderBaozi();
}
}
- 购买包子
public class OrderBaozi {
//构造器
public OrderBaozi() {
baozi b = null;
String baozistyle;
do {
baozistyle = getType();
if(baozistyle.equals("肉包子")) {
b = new roubaozi();
}else if(baozistyle.equals("菜包子")) {
b = new caibaozi();
}else {
break;
}
b.prepare();
b.baopi();
b.baoxian();
b.cooking();
}while(true);
}
// 写一个方法,可以获取客户希望订购的包子种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input 包子 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
- 包子抽象类
public abstract class baozi {
protected String name;
public abstract void prepare();
public void baopi() {
System.out.println(name + " 正在准备包皮;");
}
public void baoxian() {
System.out.println(name + " 正在准备包馅;");
}
public void cooking() {
System.out.println(name + " 正在蒸包子;");
}
public void setName(String name) {
this.name = name;
}
}
- 肉包子
public class roubaozi extends baozi{
@Override
public void prepare() {
setName("肉包子");
System.out.println(name + "正在准备!");
}
}
- 菜包子
public class caibaozi extends baozi{
@Override
public void prepare() {
setName("菜包子");
System.out.println(name+"正在准备!!");
}
}
- 结果:
- 结论:
- 优点是比较好理解,简单易操作。
- 缺点是违反了 设 计模式的 ocp 原则,即 对扩展开放,对修改关闭 。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
改进传统方式:简单工厂模式
- 改进思路:把 创建包子对象封装到一个类中,这样我们有新的包子种类时,只需要修改该类就可, 其它有创建 到 包子对象的代码就不需要修改了
- 代码改进:
- 创建一个singleFactory对象用于创建包子
public class SingleFactory {
public baozi createBaozi(String type) {
baozi b = null;
if(type.equals("肉包子")) {
b = new roubaozi();
}else if(type.equals("菜包子")) {
b = new caibaozi();
}
return b;
}
}
- 修改OrderBaozi,使用简单工厂创建包子
public class OrderBaozi {
//简单工厂模式
SingleFactory singleFactory;
baozi b = null;
//订购包子构造器
public OrderBaozi(SingleFactory singleFactory) {
setFactory(singleFactory);
}
public void setFactory(SingleFactory singleFactory) {
String type = "";
this.singleFactory = singleFactory;
do {
type = getType();
b = this.singleFactory.createBaozi(type);
//输出包子
if(b!=null) {
b.prepare();
b.baopi();
b.baoxian();
b.cooking();
}else {
System.out.println("订购失败");
break;
}
}while(true);
}
// 写一个方法,可以获取客户希望订购的包子种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input 包子 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
- 修改main方法
public class baoziStore {
public static void main(String[] args) {
//传统方式
// new OrderBaozi();
//简单工厂模式
new OrderBaozi(new SingleFactory());
}
}
- 介绍简单工厂模式:
- 简单工厂模式是属于创建型模式 ,是工厂模式的一种。 简单工厂模式是由一个工厂对象决定创建出哪一 种产品类 的实例 。简单工厂模式是工厂模式家族中最简单实用的模式
- 简单工厂模式:定义了一个创建对象的类,由这个类来 封装实例化对象的行为代码
- 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
工厂模式
- 工厂方法模式介绍
- 工厂方法模式设计方案:将包子项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将 对象的实例化推迟到子类 。
- 实例演示:
- 需求:包子项目新的需求:客户在点包子时,可以根据不同地点,点不同口味的包子,比如深圳肉包子,北京肉包子
- 代码演示:
- 包子抽象类
public abstract class BaoZi {
protected String name;
public abstract void prepare();
public void baopi() {
System.out.println(name + " 正在准备包皮;");
}
public void baoxian() {
System.out.println(name + " 正在准备包馅;");
}
public void cooking() {
System.out.println(name + " 正在蒸包子;");
}
public void setName(String name) {
this.name = name;
}
}
- 深圳肉包子,深圳菜包子:
public class SzRouBaozi extends BaoZi{
@Override
public void prepare() {
setName("深圳肉包子");
System.out.println(name+"正在准备了");
}
}
public class SzCaiBaoZi extends BaoZi{
@Override
public void prepare() {
setName("深圳菜包子");
System.out.println(name+"正在准备了");
}
}
- 北京菜包子,北京菜包子:
public class BjRouBaoZi extends BaoZi{
@Override
public void prepare() {
setName("北京肉包子");
System.out.println(name+"正在准备了");
}
}
public class BjCaiBaoZi extends BaoZi{
@Override
public void prepare() {
setName("北京菜包子");
System.out.println(name+"正在准备了");
}
}
- 包子工厂抽象类
public abstract class OrderBaoZi {
//定义一个抽象方法,createBaozi , 让各个工厂子类自己实现
abstract BaoZi createBaozi(String type);
//构造器
public OrderBaoZi() {
BaoZi b=null;
String type = null;
do {
type = getType();
b = createBaozi(type);
b.prepare();
b.baopi();
b.baoxian();
b.cooking();
}while(true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input 包子 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
- 深圳包子工厂
public class SzOrderBaoZi extends OrderBaoZi{
@Override
BaoZi createBaozi(String type) {
BaoZi b = null;
if(type.equals("深圳肉包子")) {
b = new SzRouBaozi();
}else if(type.equals("深圳菜包子")){
b = new SzCaiBaoZi();
}
return b;
}
}
- 北京包子工厂
public class BjOrderBaoZi extends OrderBaoZi{
@Override
BaoZi createBaozi(String type) {
BaoZi b = null;
if(type.equals("北京肉包子")) {
b = new BjRouBaoZi();
}else if(type.equals("北京菜包子")){
b = new BjCaiBaoZi();
}
return b;
}
}
- 包子铺
public class BaoZiStore {
public static void main(String[] args) {
System.out.println("请问你身在哪里:深圳,北京");
Scanner sc = new Scanner(System.in);
String in = sc.nextLine();
if(in.equals("深圳")) {
System.out.println("欢迎来到深圳!!");
new SzOrderBaoZi();
}else if(in.equals("北京")){
System.out.println("欢迎来到北京!!");
new BjOrderBaoZi();
}
}
}
- 结果:
抽象工厂模式
- 基本介绍:
- 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将 简单工厂模式 和 工厂方法模式进行整合。
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进 或者称为进一步的抽象 。
- 将工厂抽象成两层, AbsFactory( 抽象工厂 ) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。 这样将单个的简单工厂类变成了 工厂簇更利于代码的维护和扩展。
- 实例介绍:订pizza
- 代码
- 抽象工厂AbsFactory
//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {
//让下面的工厂子类来 具体实现
public Pizza createPizza(String orderType);
}
- BjFactory
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
// TODO Auto-generated method stub
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
- LDFactory
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
Pizza pizza = null;
if (orderType.equals("cheese")) {
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new LDPepperPizza();
}
return pizza;
}
}
- OrderPizza
public class OrderPizza {
AbsFactory factory;
// 构造器
public OrderPizza(AbsFactory factory) {
setFactory(factory);
}
private void setFactory(AbsFactory factory) {
Pizza pizza = null;
String orderType = ""; // 用户输入
this.factory = factory;
do {
orderType = getType();
// factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
pizza = factory.createPizza(orderType);
if (pizza != null) { // 订购ok
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println("订购失败");
break;
}
} while (true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
工厂模式小结
-
工厂模式的意义
- 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
- 三种工厂模式 简单工厂模式、工厂方法模式、抽象工厂模式
- 设 计模式的 依赖 抽象 原则
-
细节:
- 创 建对象实例时,不要直接 new 类 , 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
- 不 要让类继承具体类,而是继承抽象类或者是 实 现 interface( 接口
- 不 要覆盖基类中已经实现的方法。