工厂模式
需求了解
看一个披萨的项目:要便于披萨种类的扩展,要便于维护
- 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
- 披萨的制作有 prepare(准备材料),bake(烘焙),cut(切割),box(打包)
- 完成披萨店订购功能
传统方式实现
实体类
package com.atguigu.factory.tradition.pizza;
/**
* 将Pizza 类做成抽象
*/
public abstract class Pizza {
/**
* 名字
*/
protected String name;
/**
* 准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
*/
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
//打包
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}
}
package com.atguigu.factory.tradition.pizza;
public class CheesePizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println(" 准备CheesePizza ");
}
}
package com.atguigu.factory.tradition.pizza;
public class GreekPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println("准备GreekPizza");
}
}
package com.atguigu.factory.tradition.pizza;
public class PepperPizza extends Pizza {
@Override
public void prepare() {
// TODO Auto-generated method stub
System.out.println("准备PepperPizza");
}
}
订购类
package com.atguigu.factory.tradition.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.tradition.pizza.CheesePizza;
import com.atguigu.factory.tradition.pizza.GreekPizza;
import com.atguigu.factory.tradition.pizza.PepperPizza;
import com.atguigu.factory.tradition.pizza.Pizza;
public class OrderPizza {
public OrderPizza() {
Pizza pizza = null;
String orderType; // 订购披萨的类型
do {
orderType = getType();
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" greek pizza ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" cheese pizza ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName(" pepper pizza ");
} else {
break;
}
//输出pizza 制作过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
客户端
package com.atguigu.factory.tradition.order;
//相当于一个客户端,发出订购
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza();
}
}
分析
- 优点是比较好理解,简单易操作
- 缺点是违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
- 比如我们这时要新增加一个Pizza的种类(Cheese披萨),我们需要做如下修改
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INzJ96jq-1689236134050)(assets/1689236101251-1.png)]
改进
- 修改代码可以接受,但是如果我们在其它的地方也有创建Pizza的代码,就意味着,也需要修改,而创建pizza的代码,往往有多处
- 把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建Pizza对象的代码就不需要修改了(简单工厂模式)
简单工厂模式
介绍
- 简单工厂模式是属于
创建型模式
,是工厂模式的一种。简单工厂模式是由个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用
的模式 - 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
- 在软件开发中,当我们会
用到大量的创建某种、某类或者某批对象时
,就会使用到工厂模式
实现
简单工厂模式
【工厂类】
package com.atguigu.factory.simplefactory.pizzastore.order;
import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
//简单工厂类
public class SimpleFactory {
/**
* 根据orderType 返回对应的Pizza 对象
*
* @param orderType
* @return
*/
public Pizza createPizza(String orderType) {
Pizza pizza = null;
System.out.println("使用简单工厂模式");
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" 希腊披萨 ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" 奶酪披萨 ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
}
【订购类】
package com.atguigu.factory.simplefactory.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
public class OrderPizza {
/**
* 定义一个简单工厂对象,这里使用的是聚合关系,如果想换成组合关系的话,直接new就行
*/
SimpleFactory simpleFactory;
Pizza pizza = null;
//构造器
public OrderPizza(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory) {
//用户需要预定什么pizza,用户输入
String orderType = "";
//设置简单工厂对象
this.simpleFactory = simpleFactory;
do {
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);
//输出pizza
if (pizza != null) {
//--if--订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println(" 订购披萨失败 ");
break;
}
} while (true);
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
*
* @return
*/
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza type:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
【主类】
package com.atguigu.factory.simplefactory.pizzastore.order;
//相当于一个客户端,发出订购
public class PizzaStore {
public static void main(String[] args) {
//使用简单工厂模式
new OrderPizza(new SimpleFactory());
System.out.println("~~退出程序~~");
}
}
【运行】
input pizza type:
greek
使用简单工厂模式
给希腊披萨 准备原材料
希腊披萨 baking;
希腊披萨 cutting;
希腊披萨 boxing;
input pizza type:
cheese
使用简单工厂模式
给制作奶酪披萨 准备原材料
奶酪披萨 baking;
奶酪披萨 cutting;
奶酪披萨 boxing;
input pizza type:
静态工厂模式(简单工厂模式的另外一种实现方式)
【工厂类】
package com.atguigu.factory.simplefactory.pizzastore.order;
import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
//简单工厂类
public class SimpleFactory {
/**
* 简单工厂模式 也叫 静态工厂模式(使用静态方法)
* @param orderType
* @return
*/
public static Pizza createPizza2(String orderType) {
Pizza pizza = null;
System.out.println("使用简单工厂模式2");
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" 希腊披萨 ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" 奶酪披萨 ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
}
【订购类】
package com.atguigu.factory.simplefactory.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
public class OrderPizza2 {
Pizza pizza = null;
String orderType = "";
public OrderPizza2() {
do {
orderType = getType();
//调用静态方法,类.方法名
pizza = SimpleFactory.createPizza2(orderType);
if (pizza != null) {
//--if-- 订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println(" 订购披萨失败 ");
break;
}
} while (true);
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
*
* @return
*/
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 "";
}
}
}
【主类】
package com.atguigu.factory.simplefactory.pizzastore.order;
//相当于一个客户端,发出订购
public class PizzaStore {
public static void main(String[] args) {
new OrderPizza2();
}
}
工厂方法模式
新需求
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza、或者是伦敦的奶略pizza、伦敦的胡椒pizza。(即不只是有Pizza种类的区别,还有地点的区别)
【思路一】
使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等,从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好(需要创建一堆类,不好管理)
【思路二】
使用工厂方法模式
介绍
- 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类
实现
Pizza实现
【实体类】
package com.atguigu.factory.factorymethod.pizzastore.pizza;
//将Pizza 类做成抽象
public abstract class Pizza {
protected String name; //名字
//准备原材料, 不同的披萨不一样,因此,我们做成抽象方法
public abstract void prepare();
public void bake() {
System.out.println(name + " baking;");
}
public void cut() {
System.out.println(name + " cutting;");
}
//打包
public void box() {
System.out.println(name + " boxing;");
}
public void setName(String name) {
this.name = name;
}
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class BJCheesePizza extends Pizza {
@Override
public void prepare() {
setName("北京的奶酪pizza");
System.out.println(" 北京的奶酪pizza 准备原材料");
}
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class BJPepperPizza extends Pizza {
@Override
public void prepare() {
setName("北京的胡椒pizza");
System.out.println(" 北京的胡椒pizza 准备原材料");
}
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class LDCheesePizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的奶酪pizza");
System.out.println(" 伦敦的奶酪pizza 准备原材料");
}
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class LDPepperPizza extends Pizza{
@Override
public void prepare() {
// TODO Auto-generated method stub
setName("伦敦的胡椒pizza");
System.out.println(" 伦敦的胡椒pizza 准备原材料");
}
}
【工厂类】
package com.atguigu.factory.factorymethod.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
* 抽象类
*/
public abstract class OrderPizza {
/**
* 定义一个抽象方法,createPizza , 让各个工厂子类自己实现
* @param orderType
* @return
*/
abstract Pizza createPizza(String orderType);
/**
* 构造器
*/
public OrderPizza() {
Pizza pizza = null;
// 订购披萨的类型
String orderType;
do {
orderType = getType();
//直接调用抽象方法,由工厂子类完成
pizza = createPizza(orderType);
//输出pizza 制作过程
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} while (true);
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
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 "";
}
}
}
package com.atguigu.factory.factorymethod.pizzastore.order;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
* 工厂子类:伦敦工厂
*/
public class LDOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new LDPepperPizza();
}
return pizza;
}
}
package com.atguigu.factory.factorymethod.pizzastore.order;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
* 工厂子类:北京工厂
*/
public class BJOrderPizza extends OrderPizza {
@Override
Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")) {
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new BJPepperPizza();
}
return pizza;
}
}
【主类】
package com.atguigu.factory.factorymethod.pizzastore.order;
public class PizzaStore {
public static void main(String[] args) {
String loc = "bj";
if (loc.equals("bj")) {
//创建北京口味的各种Pizza
new BJOrderPizza();
} else {
//创建伦敦口味的各种Pizza
new LDOrderPizza();
}
// TODO Auto-generated method stub
}
}
【运行】
input pizza 种类:
cheese
北京的奶酪pizza 准备原材料
北京的奶酪pizza baking;
北京的奶酪pizza cutting;
北京的奶酪pizza boxing;
input pizza 种类:
pepper
北京的胡椒pizza 准备原材料
北京的胡椒pizza baking;
北京的胡椒pizza cutting;
北京的胡椒pizza boxing;
input pizza 种类:
身份证创建
【需求】
输入人的姓名,创建身份证,并提供使用功能
【框架代码】
package com.atguigu.factory.factorymethod.Sample.framework;
public abstract class Product {
public abstract void use();
}
package com.atguigu.factory.factorymethod.Sample.framework;
public abstract class Factory {
public abstract Product createProduct(String owner);
}
【子类代码】
package com.atguigu.factory.factorymethod.Sample.idcard;
import com.atguigu.factory.factorymethod.Sample.framework.Product;
public class IDCard extends Product {
private String owner;
IDCard(String owner) {
System.out.println("制作" + owner + "的ID卡。");
this.owner = owner;
}
public void use() {
System.out.println("使用" + owner + "的ID卡。");
}
public String getOwner() {
return owner;
}
}
package com.atguigu.factory.factorymethod.Sample.idcard;
import com.atguigu.factory.factorymethod.Sample.framework.*;
public class IDCardFactory extends Factory {
public Product createProduct(String owner) {
return new IDCard(owner);
}
}
【主类】
package com.atguigu.factory.factorymethod.Sample;
import com.atguigu.factory.factorymethod.Sample.framework.*;
import com.atguigu.factory.factorymethod.Sample.idcard.*;
public class Main {
public static void main(String[] args) {
Factory factory = new IDCardFactory();
Product card1 = factory.createProduct("小明");
Product card2 = factory.createProduct("小红");
Product card3 = factory.createProduct("小刚");
card1.use();
card2.use();
card3.use();
}
}
【运行】
制作小明的ID卡。
制作小红的ID卡。
制作小刚的ID卡。
使用小明的ID卡。
使用小红的ID卡。
使用小刚的ID卡。
【类图】
【登场角色】
- Product(产品)
- Creator(创建者):负责生成 Product角色的抽象类,Creator角色对于实际负责生成实例的ConcreteCreator角色一无所知它唯一知道的就是,只要调用生成实例的方法(如上图4的factoryMethod方法)就可以生成Product的实例
- ConcreteProduct(具体的产品):决定具体的产品是什么,有什么用途
- ConcreteCreator(具体的创建者):生成具体的产品
【分析】
现在是生成身份证,如果要生成其他产品,只需要修改ConcreteProduct和ConcreteCreator即可,框架不用改变
【衍生问题】
package com.atguigu.factory.factorymethod.A2.idcard;
import com.atguigu.factory.factorymethod.A2.framework.Product;
public class IDCard extends Product {
private String owner;
private int serial;
IDCard(String owner, int serial) {
System.out.println("制作" + owner + "(" + serial + ")" + "的ID卡。");
this.owner = owner;
this.serial = serial;
}
public void use() {
System.out.println("使用" + owner + "(" + serial + ")" + "的ID卡。");
}
public int getSerial() {
return serial;
}
}
package com.atguigu.factory.factorymethod.A2.idcard;
import com.atguigu.factory.factorymethod.A2.framework.*;
import java.util.HashMap;
public class IDCardFactory extends Factory {
private HashMap database = new HashMap();
private int serial = 100;
protected synchronized Product createProduct(String owner) {
return new IDCard(owner, serial++);
}
public HashMap getDatabase() {
return database;
}
}
抽象工厂模式(尚硅谷版本)
介绍
- 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展
实现
【抽象工厂接口】
package com.atguigu.factory.absfactory.pizzastore.order;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;
/**
* 一个抽象工厂模式的抽象层(接口)
*/
public interface AbsFactory {
/**
* 让下面的工厂子类来 具体实现
* @param orderType
* @return
*/
public Pizza createPizza(String orderType);
}
【工厂子类】
package com.atguigu.factory.absfactory.pizzastore.order;
import com.atguigu.factory.absfactory.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;
//这是工厂子类
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new BJCheesePizza();
} else if (orderType.equals("pepper")){
pizza = new BJPepperPizza();
}
return pizza;
}
}
package com.atguigu.factory.absfactory.pizzastore.order;
import com.atguigu.factory.absfactory.pizzastore.pizza.LDCheesePizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.LDPepperPizza;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if (orderType.equals("cheese")) {
pizza = new LDCheesePizza();
} else if (orderType.equals("pepper")) {
pizza = new LDPepperPizza();
}
return pizza;
}
}
【订购】
package com.atguigu.factory.absfactory.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.absfactory.pizzastore.pizza.Pizza;
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) {
//--if--订购ok
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println("订购失败");
break;
}
} while (true);
}
/**
* 写一个方法,可以获取客户希望订购的披萨种类
* @return
*/
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 "";
}
}
}
【主类】
package com.atguigu.factory.absfactory.pizzastore.order;
public class PizzaStore {
public static void main(String[] args) {
//new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
抽象工厂模式(《图解设计模式》)
介绍
- 抽象工厂将抽象零件组装成为抽象产品,只关心接口,不关心零件的具体实现
- 有多个具体工厂才适合使用抽象工厂模式
案例实现
【抽象类】
package com.atguigu.factory.absfactory.Sample.factory;
/**
* 抽象工厂
*/
public abstract class Factory {
/**
* 根据指定的类名生成具体工厂的实例
* @param classname
* @return
*/
public static Factory getFactory(String classname) {
Factory factory = null;
try {
//Class.forName动态获取类信息
//使用newInstance()生成类的实例
//new的是具体工厂,后面转成抽象工厂
factory = (Factory)Class.forName(classname).newInstance();
} catch (ClassNotFoundException e) {
System.err.println("没有找到 " + classname + "类。");
} catch (Exception e) {
e.printStackTrace();
}
return factory;
}
/**
* 生成零件
* @param caption
* @return
*/
public abstract Link createLink(String caption, String url);
/**
* 生成零件
* @param caption
* @return
*/
public abstract Tray createTray(String caption);
/**
* 生成产品
* @param title
* @param author
* @return
*/
public abstract Page createPage(String title, String author);
}
package com.atguigu.factory.absfactory.Sample.factory;
/**
* 项目:Link类和Tray类的父类
*/
public abstract class Item {
/**
* 项目标题
*/
protected String caption;
public Item(String caption) {
this.caption = caption;
}
/**
* 返回HTML文件的内容
* @return
*/
public abstract String makeHTML();
}
package com.atguigu.factory.absfactory.Sample.factory;
/**
* 表示HTML的超链接
* 因为Link没有实现Item的抽象方法,因此,Link也是抽象类
*/
public abstract class Link extends Item {
protected String url;
public Link(String caption, String url) {
super(caption);
this.url = url;
}
}
package com.atguigu.factory.absfactory.Sample.factory;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
/**
* 抽象表示HTML页面(Link和Tray可以理解为抽象零件,Page可以理解为抽象产品)
*/
public abstract class Page {
/**
* 页面标题
*/
protected String title;
/**
* 页面字段
*/
protected String author;
protected ArrayList content = new ArrayList();
public Page(String title, String author) {
this.title = title;
this.author = author;
}
public void add(Item item) {
content.add(item);
}
/**
* 1、根据页面标题确认文件名
* 2、调用makeHTML方法将自身保存的HTML内容写入到文件中
*/
public void output() {
try {
String filename = title + ".html";
Writer writer = new FileWriter(filename);
writer.write(this.makeHTML());
writer.close();
System.out.println(filename + " 编写完成。");
} catch (IOException e) {
e.printStackTrace();
}
}
public abstract String makeHTML();
}
package com.atguigu.factory.absfactory.Sample.factory;
import java.util.ArrayList;
/**
* 托盘类
* 里面可以包含多个Link和多个Tray,可以理解为上面放置了很多项目
* 没有实现父类的抽象方法,该类也是抽象类
*/
public abstract class Tray extends Item {
protected ArrayList tray = new ArrayList();
public Tray(String caption) {
super(caption);
}
/**
* 添加项目
* @param item
*/
public void add(Item item) {
tray.add(item);
}
}
【具体工厂一:创建列表形式的页面】
package com.atguigu.factory.absfactory.Sample.listfactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
/**
* 具体工厂
*/
public class ListFactory extends Factory {
public Link createLink(String caption, String url) {
return new ListLink(caption, url);
}
public Tray createTray(String caption) {
return new ListTray(caption);
}
public Page createPage(String title, String author) {
return new ListPage(title, author);
}
}
package com.atguigu.factory.absfactory.Sample.listfactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
public class ListLink extends Link {
public ListLink(String caption, String url) {
super(caption, url);
}
public String makeHTML() {
return " <li><a href=\"" + url + "\">" + caption + "</a></li>\n";
}
}
package com.atguigu.factory.absfactory.Sample.listfactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
import java.util.Iterator;
public class ListPage extends Page {
public ListPage(String title, String author) {
super(title, author);
}
public String makeHTML() {
StringBuffer buffer = new StringBuffer();
buffer.append("<html><head><title>" + title + "</title></head>\n");
buffer.append("<body>\n");
buffer.append("<h1>" + title + "</h1>\n");
buffer.append("<ul>\n");
Iterator it = content.iterator();
while (it.hasNext()) {
Item item = (Item) it.next();
buffer.append(item.makeHTML());
}
buffer.append("</ul>\n");
buffer.append("<hr><address>" + author + "</address>");
buffer.append("</body></html>\n");
return buffer.toString();
}
}
package com.atguigu.factory.absfactory.Sample.listfactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
import java.util.Iterator;
public class ListTray extends Tray {
public ListTray(String caption) {
super(caption);
}
public String makeHTML() {
StringBuffer buffer = new StringBuffer();
buffer.append("<li>\n");
buffer.append(caption + "\n");
buffer.append("<ul>\n");
Iterator it = tray.iterator();
while (it.hasNext()) {
Item item = (Item) it.next();
buffer.append(item.makeHTML());
}
buffer.append("</ul>\n");
buffer.append("</li>\n");
return buffer.toString();
}
}
【具体工厂二:创建表格形式的页面】
package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
/**
* 多个具体工厂
*/
public class TableFactory extends Factory {
public Link createLink(String caption, String url) {
return new TableLink(caption, url);
}
public Tray createTray(String caption) {
return new TableTray(caption);
}
public Page createPage(String title, String author) {
return new TablePage(title, author);
}
}
package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
public class TableLink extends Link {
public TableLink(String caption, String url) {
super(caption, url);
}
public String makeHTML() {
return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";
}
}
package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
import java.util.Iterator;
public class TablePage extends Page {
public TablePage(String title, String author) {
super(title, author);
}
public String makeHTML() {
StringBuffer buffer = new StringBuffer();
buffer.append("<html><head><title>" + title + "</title></head>\n");
buffer.append("<body>\n");
buffer.append("<h1>" + title + "</h1>\n");
buffer.append("<table width=\"80%\" border=\"3\">\n");
Iterator it = content.iterator();
while (it.hasNext()) {
Item item = (Item)it.next();
buffer.append("<tr>" + item.makeHTML() + "</tr>");
}
buffer.append("</table>\n");
buffer.append("<hr><address>" + author + "</address>");
buffer.append("</body></html>\n");
return buffer.toString();
}
}
package com.atguigu.factory.absfactory.Sample.tablefactory;
import com.atguigu.factory.absfactory.Sample.factory.*;
import java.util.Iterator;
public class TableTray extends Tray {
public TableTray(String caption) {
super(caption); // 使用super(...)表达式
}
public String makeHTML() {
StringBuffer buffer = new StringBuffer();
buffer.append("<td>");
buffer.append("<table width=\"100%\" border=\"1\"><tr>");
buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
buffer.append("</tr>\n");
buffer.append("<tr>\n");
Iterator it = tray.iterator();
while (it.hasNext()) {
Item item = (Item) it.next();
buffer.append(item.makeHTML());
}
buffer.append("</tr></table>");
buffer.append("</td>");
return buffer.toString();
}
}
【委托加工】
package com.atguigu.factory.absfactory.Sample;
import com.atguigu.factory.absfactory.Sample.factory.*;
/**
* 使用工厂将零件组装成为产品
* 该类没有使用任何具体零件、产品、工厂,只使用抽象的
*/
public class Main {
public static void main(String[] args) {
String arg = "com.atguigu.factory.absfactory.Sample.listfactory.ListFactory";
//创建工厂
Factory factory = Factory.getFactory(arg);
//创建零件
Link people = factory.createLink("人民日报", "http://www.people.com.cn/");
Link gmw = factory.createLink("光明日报", "http://www.gmw.cn/");
Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/");
Link excite = factory.createLink("Excite", "http://www.excite.com/");
Link google = factory.createLink("Google", "http://www.google.com/");
Tray traynews = factory.createTray("日报");
traynews.add(people);
traynews.add(gmw);
Tray trayyahoo = factory.createTray("Yahoo!");
trayyahoo.add(us_yahoo);
trayyahoo.add(jp_yahoo);
Tray traysearch = factory.createTray("检索引擎");
traysearch.add(trayyahoo);
traysearch.add(excite);
traysearch.add(google);
//组装产品
Page page = factory.createPage("LinkPage", "杨文轩");
page.add(traynews);
page.add(traysearch);
page.output();
}
}
【运行】
LinkPage.html 编写完成。
Process finished with exit code 0
生成的文件(列表形式)
<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<ul>
<li>
日报
<ul>
<li><a href="http://www.people.com.cn/">人民日报</a></li>
<li><a href="http://www.gmw.cn/">光明日报</a></li>
</ul>
</li>
<li>
检索引擎
<ul>
<li>
Yahoo!
<ul>
<li><a href="http://www.yahoo.com/">Yahoo!</a></li>
<li><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></li>
</ul>
</li>
<li><a href="http://www.excite.com/">Excite</a></li>
<li><a href="http://www.google.com/">Google</a></li>
</ul>
</li>
</ul>
<hr><address>杨文轩</address></body></html>
生成的文件(表格形式)
<html><head><title>LinkPage</title></head>
<body>
<h1>LinkPage</h1>
<table width="80%" border="3">
<tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>日报</b></td></tr>
<tr>
<td><a href="http://www.people.com.cn/">人民日报</a></td>
<td><a href="http://www.gmw.cn/">光明日报</a></td>
</tr></table></td></tr><tr><td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="3"><b>检索引擎</b></td></tr>
<tr>
<td><table width="100%" border="1"><tr><td bgcolor="#cccccc" align="center" colspan="2"><b>Yahoo!</b></td></tr>
<tr>
<td><a href="http://www.yahoo.com/">Yahoo!</a></td>
<td><a href="http://www.yahoo.co.jp/">Yahoo!Japan</a></td>
</tr></table></td><td><a href="http://www.excite.com/">Excite</a></td>
<td><a href="http://www.google.com/">Google</a></td>
</tr></table></td></tr></table>
<hr><address>杨文轩</address></body></html>
角色
AbstractProduct(抽象产品)
:负责定义抽象零件和产品的接口(API),如上面的Link、Tray、Page类AbstractFactory(抽象工厂)
:负责定义生成抽象产品的接口(API),如上面的Factory类Client(委托者)
:委托工厂加工产品,调用AbstractFactory 角色和AbstractProduct角色的接(API),如上面的Main类ConcreteProduct(具体产品)
:负责实现AbstractProduct角色的接口,如上面的ListLink类、ListTray类和ListPage类;TableLink类、TableTray类和TablePage类ConcreteFactory( 具体工厂)
:负责实现AbstractFactory角色的接口,如上面的Listfactory类、Tablefactory类
分析
- 容易增加具体工厂:只需要编写Factory、LinkTray、Page这4个类的子类,实现抽象方法
- 难以增加新零件:如在factory包中增加一个表示图像的Picture零件,需要在抽象工厂中增加一个createPicture的方法,所有的具体工厂都需要新增代码,具体工厂越多,工作量越大
简单工厂模式在JDK中的应用
小结
- 工厂模式的意义:
将实例化对象的代码提取出来,放到一个类中统一管理和维护
,达到和主项目的依赖关系的解耦,从而提高项目的扩展和维护性 - 工厂模式有三种
工厂模式体现依赖抽象原则的点:
- 创建对象实例时,不要直接 new 类,而是把这个new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用,应该引用抽象类
- 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
- 不要覆盖基类中已经实现的方法
文章说明
本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。