文章目录
二、工厂模式
- 点果汁案例
1. 简单工厂模式
(不属于设计模式,像编程习惯)
1.1 说明
结构
:简单工厂包含- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 :实现或者继承抽象产品的子类
- 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。
1.2 优缺点
优点
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避 免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户 代码修改的可能性,更加容易扩展
缺点
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
1.3 UML类图
1.4 代码
- A类果汁
public class AJuice extends Juice {
@Override
public String getName() {
return "A类果汁";
}
}
- B类果汁
public class BJuice extends Juice {
@Override
public String getName() {
return "B类果汁";
}
}
- 果汁抽象类
public abstract class Juice {
public abstract String getName();
public void addSugar(){
System.out.println("加糖");
}
public void addIce(){
System.out.println("加冰");
}
public void addHot(){
System.out.println("加热");
}
}
- 果汁商店类
public class JuiceStore { public Juice orderJuice(String type){ SimpleJuiceFactory factory = new SimpleJuiceFactory(); Juice juice = factory.creatJuice(type); juice.addHot(); juice.addIce(); juice.addSugar(); return juice; }}
- 果汁工厂类
public class SimpleJuiceFactory { public Juice creatJuice(String type){ Juice juice = null; if("A".equalsIgnoreCase(type)){ juice = new AJuice(); }else if("B".equalsIgnoreCase(type)){ juice = new BJuice(); }else { throw new RuntimeException("不好意思,没有这种果汁"); } return juice; }}
- 客户测试类
public class Client { public static void main(String[] args) { JuiceStore store = new JuiceStore(); Juice juice = store.orderJuice("A"); System.out.println(juice.getName()); Juice juice1 = store.orderJuice("B"); System.out.println(juice1.getName()); Juice juice2 = store.orderJuice("C"); System.out.println(juice2.getName()); }}
- 测试结果
加热加冰加糖A类果汁加热加冰加糖B类果汁Exception in thread "main" java.lang.RuntimeException: 不好意思,没有这种果汁
2. 静态工厂
(不属于设计模式,像编程习惯)
- 把工厂类中的创建对象的功能定义为静态的
public class SimpleJuiceFactory {
public static Juice creatJuice(String type){
Juice juice = null;
if("A".equalsIgnoreCase(type)){
juice = new AJuice();
}else if("B".equalsIgnoreCase(type)){
juice = new BJuice();
}else {
throw new RuntimeException("不好意思,没有这种果汁");
}
return juice;
}
}
3. 工厂方法模式
1.1 说明
结构
:主要角色- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂 方法来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同 具体工厂之间一一对应。
1.2 优缺点
优点
-
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
-
在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改, 满足开闭原则;
缺点
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
1.3 UML类图
1.4 代码
- 创建果汁工厂接口
public interface JuiceFacotry { //创建果汁对象的方法 Juice createJuice();}
- 生产A果汁的工厂
public class AFactory implements JuiceFacotry{ @Override public Juice createJuice() { return new AJuice(); }}
- 生产B果汁的工厂
public class BFactory implements JuiceFacotry{ @Override public Juice createJuice() { return new BJuice(); }}
- 果汁类
public abstract class Juice {
public abstract String getName();
public void addSugar(){
System.out.println("加糖");
}
public void addIce(){
System.out.println("加冰");
}
public void addHot(){
System.out.println("加热");
}
}
- A、B果汁类
public class AJuice extends Juice{
@Override
public String getName() {
return "A类果汁";
}
}
public class BJuice extends Juice{
@Override
public String getName() {
return "B类果汁";
}
}
- 果汁商店同上
- 测试类
public class Client {
public static void main(String[] args) {
JuiceStore store = new JuiceStore();
JuiceFacotry facotry1 = new AFactory();
store.setJuiceFacotry(facotry1);
Juice juice = store.orderJuice();
System.out.println(juice.getName());
JuiceFacotry facotry2 = new BFactory();
store.setJuiceFacotry(facotry2);
Juice juice2 = store.orderJuice();
System.out.println(juice2.getName());
}
}
- 测试结果
加糖加冰加热A类果汁加糖加冰加热B类果汁
4. 抽象工厂模式
需求:发生改变,增加A风格的A类甜点、B风格的B类甜点,为了避免类的爆炸(不停的创建类),使用抽象工厂
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生 产多个等级的产品。
1 说明
产品族和同一级别的观念
结构
:主要角色
- 抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法,可以 创建多个不同等级的产品。
- 具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创 建。
- 抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多 个抽象产品。
- 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
使用场景
- 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空 调等。
- 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
- 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结 构。
2. 优缺点
优点
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
3. UML类图
4. 代码
- 风格工厂的接口
public interface StyleFactory { //生产果汁的功能 Juice createJuice(); //生产甜品的功能 SweetFood createSweet();}
- 果汁类、甜品类、AB果汁类、AB甜品类
public abstract class Juice { public abstract String getName(); public void addSugar(){ System.out.println("加糖"); } public void addIce(){ System.out.println("加冰"); } public void addHot(){ System.out.println("加热"); }}public class AJuice extends Juice { @Override public String getName() { return "A类果汁"; }}public class BJuice extends Juice { @Override public String getName() { return "B类果汁"; }}/** * 甜品抽象类 */public abstract class SweetFood { public abstract void show();}public class ASweet extends SweetFood{ @Override public void show() { System.out.println("A甜品"); }}public class BSweet extends SweetFood{ @Override public void show() { System.out.println("B甜品"); }}
- A类工厂
public class AStyleFactory implements StyleFactory { @Override public Juice createJuice() { return new AJuice(); } @Override public SweetFood createSweet() { return new ASweet(); }}
- B类工厂
/** * B */public class BStyleFactory implements StyleFactory { @Override public Juice createJuice() { return new BJuice(); } @Override public SweetFood createSweet() { return new BSweet(); }}
- 测试类
public class Client { public static void main(String[] args) { StyleFactory bfactory = new BStyleFactory(); Juice bJuice = bfactory.createJuice(); SweetFood bSweet = bfactory.createSweet(); System.out.println(bJuice.getName()); bSweet.show(); StyleFactory afactory = new AStyleFactory(); Juice aJuice = afactory.createJuice(); SweetFood aSweet = afactory.createSweet(); System.out.println(aJuice.getName()); aSweet.show(); }}
- 测试结果
B类果汁B甜品A类果汁A甜品
5. 模式扩展(简单工厂+配置文件接触耦合)
1. 说明
可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全 类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可。
2. 代码演示
- 创建一个配置文件
A=DP02工厂模式.DP04ConfigFactory.AJuiceB=DP02工厂模式.DP04ConfigFactory.BJuice
- 果汁广场改造
public class JuiceFactory {
private static HashMap<String,Juice> map = new HashMap<>();
static {
Properties prop = new Properties();
try {
prop.load(new InputStreamReader(JuiceFactory.class.getClassLoader().getResourceAsStream("bean.properties"),"GBK"));
//拿到里面所有的键
Set<Object> keys = prop.keySet();
for (Object key :
keys) {
String className = prop.getProperty((String) key);
//通过反射创建对象
Class clazz = Class.forName(className);
Juice juice = (Juice)clazz.newInstance();
//将名称和对象存储到容器中
map.put((String)key,juice);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//根据名称获取对象
public static Juice createJuice(String name){
return map.get(name);
}
}
- 测试类
public class Client {
public static void main(String[] args) {
Juice juice = JuiceFactory.createJuice("A");
System.out.println(juice.getName());
System.out.println("============");
Juice juice1 = JuiceFactory.createJuice("B");
System.out.println(juice1.getName());
}
}
3. 好处
- 静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及 创建对象写在静态代码块中,目的就是只需要执行一次。
6. 实际应用案例
1. Iterator
方法
- Collection接口是抽象工厂类
- ArrayList是具体的工厂类;
- Iterator接口是抽象商品类,
- ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品 类的对象。
2. 其他案例
- DateForamt类中的getInstance()方法使用的是工厂模式;
- Calendar类中的getInstance()方法使用的是工厂模式;
员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及 创建对象写在静态代码块中,目的就是只需要执行一次。
6. 实际应用案例
1. Iterator
方法
[外链图片转存中…(img-vlvKyHFk-1621781102112)]
- Collection接口是抽象工厂类
- ArrayList是具体的工厂类;
- Iterator接口是抽象商品类,
- ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品 类的对象。
2. 其他案例
- DateForamt类中的getInstance()方法使用的是工厂模式;
- Calendar类中的getInstance()方法使用的是工厂模式;