工厂模式
三种类型,简单工厂、工厂模式、抽象工厂。
将实例的创建交给工厂,像现实生活中的工厂一样批量生产产品。
简单工厂模式
基本介绍
- 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
- 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为
- 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
实例演示
通过简单工厂模式来播种蔬菜。
1)UML类图
2)创建蔬菜接口
播种不同的蔬菜,所有蔬菜都是同样的方法,我们直接定义一个接口来让其他蔬菜来实现这个接口。
public interface Vegetable {
public void sowVegetable();
public void growthVegetable();
public void fruitVegetable();
}
3)添加蔬菜种类
这里以胡萝卜为例,添加其他的蔬菜同理。
public class Carrot implements Vegetable {
@Override
public void sowVegetable() {
System.out.println("播种了:胡萝卜");
}
@Override
public void growthVegetable() {
System.out.println( "胡萝卜成长了");
}
@Override
public void fruitVegetable() {
System.out.println("收获了:胡萝卜");
}
}
4)创建简单工厂
工厂模式的核心就是通过工厂来实例化对象,而不是通过用户来创建。
这里我的想法是,给工厂传递一个蔬菜种类名称,然后工厂给你返回一个蔬菜实例。
public class VegetableSimpleFactory {
Vegetable vegetable;
public Vegetable growingVegetable(String variety){
if (variety.equals("胡萝卜")){
vegetable = new Carrot();
} else if (variety.equals("豆薯")){
vegetable = new Jicama();
} else if (variety.equals("萝卜")){
vegetable = new Radish();
} else if (variety.equals("大头菜")){
vegetable = new Turnip();
}
return vegetable;
}
}
5)创建工人
其实这里只要一个工厂已经实现了,但是这里我想要当我通过获得了一类蔬菜以后,然后通过工人来帮我们进行播种和收获。
public class Worker {
VegetableSimpleFactory simpleFactory = new VegetableSimpleFactory();
public void receiveMsg(String variety){
Vegetable vegetable = simpleFactory.growingVegetable(variety);
vegetable.sowVegetable();
vegetable.growthVegetable();
vegetable.fruitVegetable();
}
}
6)测试
public class Test {
public static void main(String[] args) {
Worker worker = new Worker();
worker.receiveMsg("胡萝卜");
}
}
小结
简单工厂模式只有一个工厂,如果需要添加蔬菜需要修改工厂代码,不方便。
工厂方法模式
模式介绍
定义了一个创建对象的抽象方法,由子类决定要实例化的类。
工厂方法模式将对象的实例化推迟到子类。
抽象类定义了实例化的抽象方法,具体的实现根据子类的重写
演示
1)UML类图
注:vegetable的接口和类和前面都是一样的,这里就不重复演示,更改的只是蔬菜的名字。
2)创建工厂抽象类
这里已经定义好了对蔬菜的操作,对蔬菜种类的获取留给子类自己重写制定实现。
public abstract class VegetableFactory {
public abstract Vegetable growingVegetable();
public void creatVegetable(){
Vegetable vegetable = growingVegetable();
vegetable.sowVegetable();
vegetable.growthVegetable();
vegetable.fruitVegetable();
}
}
3)创建工厂实例
这里以其中的茎类蔬菜工厂为例。
public class StemVegetableFactory extends VegetableFactory{
@Override
public Vegetable growingVegetable() {
return new Stem();
}
}
4)测试
public class Test2 {
public static void main(String[] args) {
StemVegetableFactory stemVegetableFactory = new StemVegetableFactory();
stemVegetableFactory.creatVegetable();
}
}
小结
方便了工厂类型的扩展。
抽象工厂模式
基本介绍
- 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展
实例演示
对前面的蔬菜工厂进行改进
1)UML类图
这里就不做接下来的演示,原理就是将抽象类换为了接口,可以根据这UML类图进行进一步处理。
工厂模式在JDK - Calendar应用的源码分析
使用的是简单工厂模式。
部分源码
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
总结
工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
设计模式的依赖抽象原则
创建对象实例时,不要直接 new 类, 而是把这个new 类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要直接持有具体类的引用。
不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
不要覆盖基类中已经实现的方法。
迭代器模式
迭代器就是遍历。将集合中的数组,在不告知内部信息的情况下遍历。在Java集合类中也提供了迭代器的使用。
基本介绍
-
迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式
-
如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决
-
迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
实例演示
现有的商家菜单系统的菜单由Menu类表示,主要属性为:处理价格,菜单名和描述。其主要由4种数据结构实现:传统数组,arrayList, List, Map。现假设要实现一个美团,该系统要对接现有的商家菜单系统,但又不能更改现有的商家菜单系统,请使用迭代器模式,完成商家系统的对接。
1)UML类图
2)创建菜品类
菜单中肯定是装的是菜品,没有菜品哪来的菜单,更何谈将菜单中的菜品遍历出来。
这里只是简单的定义,具体的实现看源码
/*
* 菜单中的菜品的定义
* */
public class Dishes {
private int price;
private String menuName;
private String desc; //菜单描述
}
3)创建菜单类
这里创建了4个菜单,其中有很多相似的地方,其实可以将相似的地方抽取出来作为一个接口,然后全部来实现就可以了,这里就不演示了。
public class Menu1 {
Dishes[] menu1;
private int index = 0;
/*
* 这里我们直接用构造器来构建菜单
* */
public Menu1(int size) {
menu1 = new Dishes[size];
}
public void add(Dishes menu){
menu1[index] = menu;
index++;
}
/*
* 创建一个迭代器,每一个菜单存储菜品的方式都是不同的,那么就需要
* 不同的迭代器来输出
* */
public Iterator<Dishes> creatIterator(){
return new Menu1Iterator(menu1);
}
}
4)创建出4个菜单的迭代器
自定义的迭代器是通过实现Java自带的迭代器接口实现。
/*
* 第一个菜单通过传统数组存储
* */
public class Menu1Iterator implements Iterator<Dishes> {
Dishes[] menu1;
private int index = 0; // 遍历数组时需要的数组下标
// 通过构造器传入需要迭代的数组
public Menu1Iterator(Dishes[] menu1) {
this.menu1 = menu1;
}
/*
* 判断数组中是否含有下一个元素,如果有返回为真,如果数组下标
* 超过了数组的长度或者数组当前下标不含有元素,那么返回为假
* */
@Override
public boolean hasNext() {
if (index > menu1.length-1 || menu1[index] == null){
return false;
} else {
return true;
}
}
/*
* 返回当前这个数组下标上的元素,并将数组下标向后移一位
* */
@Override
public Dishes next() {
Dishes dishes = menu1[index];
index++;
return dishes;
}
}
5)编写测试类
也就是题目中的美团,其实迭代器的原理是不暴露内部的具体信息,这里为了测试的简便就直接在测试类中编写了菜品的信息。完整的应该是直接在原有的系统中创建的时候就已经将菜单填充完毕,我们美团系统直接调用菜单就可以了。
/*
* 测试类:这里是在测试类中向每一个菜单添加添加菜品,当然也可以
* 直接才创建菜单的时候进行添加
*
* 注:其他菜单测试同理
* */
public class ClientMeiTuan {
public static void main(String[] args) {
Menu1 menu1 = new Menu1(5);
Dishes dishes1 = new Dishes(20, "菜名1", "川菜");
Dishes dishes2 = new Dishes(21, "菜名2", "川菜");
Dishes dishes3 = new Dishes(22, "菜名3", "川菜");
Dishes dishes4 = new Dishes(23, "菜名4", "川菜");
Dishes dishes5 = new Dishes(24, "菜名5", "川菜");
menu1.add(dishes1);
menu1.add(dishes2);
menu1.add(dishes3);
menu1.add(dishes4);
menu1.add(dishes5);
Iterator<Dishes> dishesIterator1 = menu1.creatIterator();
while (dishesIterator1.hasNext()){
System.out.println(dishesIterator1.next().toString());
}
}
}
6)结果
小结
迭代器就是自己编写遍历规则,其他类调用的时候,直接调用类中创建的迭代器就可以,不必知道菜单的具体信息。
当然还有很多升级的空间,如可以将所有的菜单存储在一个集合中,然后依次遍历,输出所有菜单的结果。
补充
在Java中的很多集合类如ArrayList等,内部也都是通过获取迭代器的方式来进行遍历的。