java设计模式 (二)
创建型模式
单例模式
Singleton pattern
现实场景
双11, 小华收快递, 早上圆通快递叫他下楼收快递, 刚上来, 顺丰快递叫他下楼收快递,.然后没多久EMS, 中通等相继打来叫收快递.
收件人小华就相当于一个单列, 不管哪一家快递送来快递, 快递上面的小华都是同一个, 相当于同一个对象.
定义
一个类只有一个实例, 而且自动实例化并向整个系统提供这个实例
表现形式
-
饿汉式单例类 : 类加载时, 进行对象实例化.
类加载的时候实例化对象
构造函数私有 避免外界利用构造函数直接创建对象
不能继承
类加载时生成实例对象, 懒汉式更加节省资源利用率
-
懒汉式单例类 : 第一次引用类时, 才进行对象实例化.
第一次调用的时候实例化对象
构造函数私有 避免外界利用构造函数直接创建对象
不能继承
需要用synchronized 同步方法 速度没有饿汉式快
使用场景
- 一个类有且仅有一个实例
- 多实例会造成不良反应
- 需要一行共享访问点或者共享数据
- 创建对象需要消耗过多资源
- 需要定义大量金泰常量或者金泰方法 (也可以直接声明static)
注意事项
-
有状态单列, 一个状态单列类的对象一般是可变的, 通常当中状态库
-
无状态库, 无状态单例是不可变, 通常用来提供工具性
有状态需要注意
- 单例仅局限于一个JVM, 因此存在多个JVM分布式系统, 单例就会出现多个JVM中被实例. 如果无状态的单例则没问题. 因此任何使用EJB, RMI, JINI技术的分布式系统中, 银弹避免使用有状态的单列类.
- 提供JVM中会有多个类加载器, 当两个类加载器同时加载同一个类, 会出现两个实例, 此时应该尽量避免使用有状态单例类.
- 不能实现Serializable或Cloneable 接口, 则可能被反序列化或者克隆出一个新的实例, 从而破坏"唯一实例".
优点
- 只有一个实例, 减少内存开支
- 避免多重占用
- 全局访问点, 优化和共享资源访问.
缺点
- 单列无法创建子类, 扩展困难
- 测试不利, 并行开发, 如果采用单例类没有完成, 程序不能进行测试, 单列模式通常不会实现接口
- 与单一职责有冲突, 一个类应该只是实现一个逻辑, 而不关心它是否是单例, 是否使用单例模式取决于环境, 单列模式把"要单例"和业务逻辑融合在一起
- 使用注意 :
- 懒汉式 需要用到同步操作 速率上相较慢 (可以优化)
- 饿汉式 : 类加载就初始化 不需要同步操作 保证单列线程安全
饿汉式
package com.gylang.design.pattern.singleton;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class HungrySingleton {
private static HungrySingleton m_instance = new HungrySingleton();
//构造方法私有, 保证外界无法直接实例化
private HungrySingleton() {
}
//通过该方法获取实例对象
public static HungrySingleton getInstance() {
return m_instance;
}
}
Java
Copy
懒汉式
package com.gylang.design.pattern.singleton;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class LazySingleton {
private static LazySingleton singleton = null;
//构造方法私有, 保证外界无法直接实例化
private LazySingleton() {
}
//方法同步
synchronized public static LazySingleton getInstance() {
if (singleton == null) {
singleton = new LazySingleton();
}
return singleton;
}
}
Java
Copy
优化版懒汉式
使用双重检测同步延迟加载去创建单例的做法是一个非常优秀的做法,**其不但保证了单例,而且切实提高了程序运行效率。**对应的代码清单如下:
package com.gylang.design.pattern.singleton;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class LazySingleton {
private static LazySingleton singleton = null;
//构造方法私有, 保证外界无法直接实例化
private LazySingleton() {
}
//方法同步
synchronized public static LazySingleton getInstance() {
if (singleton == null) {
synchronized (LazySingleton.class){
// 只需在第一次创建实例时才同步
if (singleton == null) {
singleton = new LazySingleton();
}
}
}
return singleton;
}
}
Java
Copy
工厂方法模式
Factory Method Pattern
现实场景
奔驰的制造类类似设计模式中的工程模式, 可以看出奔驰车是一个抽象的产品, 而C180和E260是两个具体的产品, 生产奔驰的厂家是一个抽象工程, 而具体工厂是生成C180的厂家和生产E260的厂家.
工厂模式分类
简单工厂模式
一个工厂类处于对产品实例化的中心位置, 他知道每个产品, 它决定每个产品应当被实例化, 这个模式的优点允许客户端相对独立与产品的创建过程, 并且在系统引用新产品的时候无需修改客户端么即在某种程度上支持"开-闭"原则. 当支持力度不够, 一旦有新的产品添加到系统中, 则需要修改工厂类, 将必要的逻辑添加到工厂类中.
工厂方法模式
工厂方法模式具有多态性,即保存了简单工厂模式的优点, 又克服了它的缺点, 首先工厂方法模式中, 核心的工厂方法不再负责所有产品的创建, 而是将其具体的工作交给子类去做, 这个核心类成为一个抽象角色, 仅负责给出具体的工厂必须实现的接口, 而不接触哪个产品类当做被实例化得细节, 使得这种工厂方法模式可以允许系统在不修改具体工厂角色的情况下引进新的产品.
抽象工厂模式
所有工厂模式中最为抽象和最为具有一般性的一种形态, 抽象工厂模式与工厂方法模式的最大区别就在于, 工厂方法模式针对的是一个产品的等级结构, 而抽象工厂模式则需要面对多个产品等级接口.
角色
- 抽象工厂角色 : 任何创建对象的工厂必须实现这个接口
- 具体工厂 : 该角色实现了抽象工厂接口, 含有与应用密切相关的逻辑, 并通过调用应用程序来创建产品对象.
- 抽象产品角色 : 定义产品共性, 实现对产品的最抽象定义
- 具体产品 : 该角色实现了抽象产品角色所有声明的接口, 工厂方法模式所创建的每一个对象都是某个具体产品角色的实例.
优点
- 良好封装性, 代码结构清晰 : 不用知道创建对象的过程, 降低模块之间的耦合
- 优秀的扩展性 : 增加产品类的情况下, 只要适当地修改具体的工厂类或者扩展一个工厂类, 就可以适应变化
- 屏蔽产品类 : 产品类的实现如何变化, 调用者不用关系, 只需要关系产品的接口, 只要接口保持不变, 系统的上层模块就不需要发成变化.
- 典型解耦框架 : 高层模块只需要知道产品的抽象类, 其他的实现类不需要关系
- 符合
依赖倒置, 迪米特, 里氏替换
场景
- 创建一个对象的代替品, 当需要增加一个工厂类进行管理对象的实例.
- 需要灵活可扩展的框架时.
- 可以使用与异构项目,
- 工厂模式可以在测试驱动开发的框架下使用,
实例
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public interface Benz {
void carColor();
void carSpeed();
void carPrice();
}
Java
Copy
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class BenzC180 implements Benz {
public BenzC180() {
this.carColor();
this.carSpeed();
this.carPrice();
}
@Override
public void carColor() {
System.out.println("奔驰C180颜色银白色");
}
@Override
public void carSpeed() {
System.out.println("奔驰C180速度280Km/h");
}
@Override
public void carPrice() {
System.out.println("奔驰C180价格100W");
}
}
Java
Copy
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class BenzE260 implements Benz {
public BenzE260() {
this.carColor();
this.carSpeed();
this.carPrice();
}
@Override
public void carColor() {
System.out.println("奔驰E260颜色黑色");
}
@Override
public void carSpeed() {
System.out.println("奔驰E260速度320Km/h");
}
@Override
public void carPrice() {
System.out.println("奔驰E260价格150W");
}
}
Java
Copy
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public interface BenzFactory {
public Benz createCar();
}
Java
Copy
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class C180Factory implements BenzFactory {
@Override
public Benz createCar() {
return new BenzC180();
}
}
Java
Copy
package com.gylang.design.pattern.factory.method;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class E260Factory implements BenzFactory {
@Override
public Benz createCar() {
return new BenzE260();
}
}
Java
Copy
package com.gylang.design.pattern.factory.method;
import com.gylang.design.principe.dependenc_down.Beanz;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/3,
*/
public class Main {
public static void main(String[] args) {
System.out.println("老板, 给我介绍下C180!");
BenzFactory benzFactory = new C180Factory();
benzFactory.createCar();
System.out.println("======================");
System.out.println("老板, 给我介绍下E260!");
BenzFactory benzFactory1 = new E260Factory();
benzFactory1.createCar();
System.out.println("======================");
System.out.println("两辆车试驾完, 买了其中一辆车");
}
}
Java
Copy
老板, 给我介绍下C180!
奔驰C180颜色银白色
奔驰C180速度280Km/h
奔驰C180价格100W
======================
老板, 给我介绍下E260!
奔驰E260颜色黑色
奔驰E260速度320Km/h
奔驰E260价格150W
======================
两辆车试驾完, 买了其中一辆车
Process finished with exit code 0
抽象工厂模式
Abstract Factory Pattern
现实场景
以dota为例, dota分两个阵营, 一个为近卫军团, 一个为天灾军团. 每个军团都有力量型, 敏捷性, 智力型英雄.
两个阵营里面的英雄的生产类似于设计模型的抽象工厂设计模型, 两个阵营就是两个不同的具体工厂, 阵营里面的三种英雄类型就是抽象产品, 每个类型里面的具体英雄就是具体产品.
角色
- 抽象工厂角色 : 任何创建对象的工厂必须实现这个接口
- 具体工厂 : 该角色实现了抽象工厂接口, 含有与应用密切相关的逻辑, 并通过调用应用程序来创建产品对象.
- 抽象产品角色 : 定义产品共性, 实现对产品的最抽象定义
- 具体产品 : 该角色实现了抽象产品角色所有声明的接口, 工厂方法模式所创建的每一个对象都是某个具体产品角色的实例.
优点
- 抽象工厂是工厂模式的进一步抽象, 针对的是一簇产品, 如果产品簇中只有一种产品, 抽象工厂模式就退化到工厂方法模式.
- 产品簇的约束为非公开状态, 在不同的工厂中, 各种产品之间可能具有不同的相互依赖, 这些依赖有工厂封装在其内部, 对于工厂的使用者来说这些依赖关系是不可见的.
- 生长线的扩展非常容易, 如果针对同一产品建立新的生产线, 只需要实现产品族中所有的产品接口并建立新的工厂即可.
缺点
- 最大缺点就是产品族中本身的扩展非常困难, 如果在产品族中增加一个新的产品, 则需要修改多个接口, 并影响已有的工厂类.
场景
当一个对象簇都有相同的约束时, 可以使用抽象工厂模式.
例如
应用涉及不同操作系统的时候, 可以考虑使用, 如需要三个不同平台.(windows, linux, mac)上运行, 通过抽象工厂模式, 可以屏蔽掉操作系统对应用的影响, 三个不用操作系统上的软件功能, 应用逻辑,UI都应该非常相似, 唯一不同就是调用不同的工厂方法, 由不同的产品类去处理其与操作系统的交互信息.
各类英雄 省略 力量, 智力型
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public interface IAgileHero {
void createHero();
}
Java
Copy
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class AgileHero implements IAgileHero {
private String name;
public AgileHero(String name) {
this.name = name;
}
@Override
public void createHero() {
System.out.println("创建敏捷性型英雄: " + name);
}
}
Java
Copy
英雄生产抽象工厂
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public interface IHeroFactory {
//获取力量型英雄
IStrengthHero getIStrengthHero();
//获取敏捷性英雄
IAgileHero getIAgileHero();
//获取智力型英雄
IIntellectualHero getIIntellectualHero();
}
Java
Copy
近卫军团工厂, 具体工厂
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class SentinelFactory implements IHeroFactory {
@Override
public IStrengthHero getIStrengthHero() {
return new StrengthHero("流浪剑客");
}
@Override
public IAgileHero getIAgileHero() {
return new AgileHero("剑圣");
}
@Override
public IIntellectualHero getIIntellectualHero() {
return new IntellectualHero("仙女龙");
}
}
Java
Copy
天灾军团工厂, 具体工厂
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class ScourgeFactory implements IHeroFactory {
@Override
public IStrengthHero getIStrengthHero() {
return new StrengthHero("斧王");
}
@Override
public IAgileHero getIAgileHero() {
return new AgileHero("影魔");
}
@Override
public IIntellectualHero getIIntellectualHero() {
return new IntellectualHero("召唤师");
}
}
Java
Copy
测试
package com.gylang.factory.abstract1;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Main {
public static void main(String[] args) {
IHeroFactory sentinelFactory = new SentinelFactory(); //近卫军团工厂
IStrengthHero sentinelStrengthHero = sentinelFactory.getIStrengthHero();
IAgileHero sentinelAgileHero = sentinelFactory.getIAgileHero();
IIntellectualHero sentinelIntellectualHero = sentinelFactory.getIIntellectualHero();
System.out.println("近卫军团: ");
sentinelStrengthHero.createHero();
sentinelAgileHero.createHero();
sentinelIntellectualHero.createHero();
IHeroFactory scourgeFactory = new ScourgeFactory(); //天灾军团工厂
IStrengthHero scourgelStrengthHero = scourgeFactory.getIStrengthHero();
IAgileHero scourgeAgileHero = scourgeFactory.getIAgileHero();
IIntellectualHero scourgeIntellectualHero = scourgeFactory.getIIntellectualHero();
System.out.println("天灾军团: ");
scourgelStrengthHero.createHero();
scourgeAgileHero.createHero();
scourgeIntellectualHero.createHero();
}
}
Java
Copy
近卫军团:
创建力量型英雄: 流浪剑客
创建敏捷性型英雄: 剑圣
创建智力型英雄: 仙女龙
天灾军团:
创建力量型英雄: 斧王
创建敏捷性型英雄: 影魔
创建智力型英雄: 召唤师
Process finished with exit code 0
建造者模式
Builder Pattern 也叫
生成器模式
现实场景
魅族手机和华为手机制造过程就类似于建造者模式, 可以发现其实手机构造基本一致的, 知识他们所用的硬件配件不同, 做出来的手机产品也就不同.
定义
将一个复杂对象的构建与它的表示分类, 使得同样的构建过程可以创建不同的表示.
角色
- 抽象建造者角色 : 该角色用于规范产品的各个组成部分, 并进行抽象, 一般独立于应用程序的逻辑.
- 具体建造者角色 : 该角色实现了抽象建造者中定义的所有方法, 并返回一个组建好的产品实例
- 产品角色 : 建造中的复杂对象, 一个系统会有多个产品类, 这些产品类不一定共同的接口, 可以是完全不相关联
- 导演者角色 : 该角色负责安排已有模块的顺序, 然后告诉建造者开始建造.
package com.gylang.build;
/** 产品角色
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public abstract class CellPhone {
private String cpu;
private String ram;
private String screen;
private String battery;
private String facade;
private String other;
//set 和 get
}
Java
Copy
package com.gylang.build;
/** 产品角色 mate7
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Mate7 extends CellPhone {
public Mate7() {
System.out.println("这是华为mate7手机");
}
@Override
public String toString() {
return "Mate7{" +
"cpu='" + this.getCpu() + '\'' +
", ram='" + this.getRam() + '\'' +
", screen='" + this.getScreen() + '\'' +
", battery='" + this.getBattery() + '\'' +
", facade='" + this.getFacade() + '\'' +
", other='" + this.getOther() + '\'' +
'}';
}
}
Java
Copy
package com.gylang.build;
/** 产品角色 Mx4Pro
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Mx4Pro extends CellPhone {
public Mx4Pro() {
System.out.println("这是魅族MX4 Pro手机");
}
@Override
public String toString() {
return "Mx4Pro{" +
"cpu='" + this.getCpu() + '\'' +
", ram='" + this.getRam() + '\'' +
", screen='" + this.getScreen() + '\'' +
", battery='" + this.getBattery() + '\'' +
", facade='" + this.getFacade() + '\'' +
", other='" + this.getOther() + '\'' +
'}';
}
}
Java
Copy
package com.gylang.build;
/** 抽象建造者角色
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public interface CellPhoneBuilder {
void buildCpu();
void buildRam();
void buildScreen();
void buildBattery();
void buildFacade();
void buildOthers();
CellPhone buildPhone();
}
Java
Copy
package com.gylang.build;
/** 具体建造者
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Mate7Build implements CellPhoneBuilder {
CellPhone mete7 = new Mate7();
@Override
public void buildCpu() {
mete7.setCpu("采用华为自主研发的最先芯片");
}
@Override
public void buildRam() {
mete7.setRam("4G内存");
}
@Override
public void buildScreen() {
mete7.setScreen("6寸1080P分辨率60Hz");
}
@Override
public void buildBattery() {
mete7.setBattery("3600毫安");
}
@Override
public void buildFacade() {
mete7.setFacade("使用振金材料");
}
@Override
public void buildOthers() {
mete7.setOther("屏下指纹识别");
}
@Override
public CellPhone buildPhone() {
return mete7;
}
}
Java
Copy
package com.gylang.build;
/** 具体建造者
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Mx4ProBuild implements CellPhoneBuilder {
CellPhone mx4Pro = new Mx4Pro();
@Override
public void buildCpu() {
mx4Pro.setCpu("采用魅族自主研发的最先芯片");
}
@Override
public void buildRam() {
mx4Pro.setRam("8G内存");
}
@Override
public void buildScreen() {
mx4Pro.setScreen("6寸4K分辨率144Hz");
}
@Override
public void buildBattery() {
mx4Pro.setBattery("4600毫安");
}
@Override
public void buildFacade() {
mx4Pro.setFacade("使用钛合金材料");
}
@Override
public void buildOthers() {
mx4Pro.setOther("侧边指纹识别");
}
@Override
public CellPhone buildPhone() {
return mx4Pro;
}
}
Java
Copy
package com.gylang.build;
/** 导演者角色
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class CellPhonedirector {
private CellPhoneBuilder cellPhoneBuilder;
public Mate7 buildMate7() {
cellPhoneBuilder = new Mate7Build();
cellPhoneBuilder.buildCpu();
cellPhoneBuilder.buildRam();
cellPhoneBuilder.buildScreen();
cellPhoneBuilder.buildBattery();
cellPhoneBuilder.buildFacade();
cellPhoneBuilder.buildOthers();
return (Mate7) cellPhoneBuilder.buildPhone();
}
public Mx4Pro buildMx4Pro() {
cellPhoneBuilder = new Mx4ProBuild();
cellPhoneBuilder.buildCpu();
cellPhoneBuilder.buildRam();
cellPhoneBuilder.buildScreen();
cellPhoneBuilder.buildBattery();
cellPhoneBuilder.buildFacade();
cellPhoneBuilder.buildOthers();
return (Mx4Pro) cellPhoneBuilder.buildPhone();
}
}
Java
Copy
package com.gylang.build;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Main {
public static void main(String[] args) {
CellPhonedirector director = new CellPhonedirector();
//华为手机定制
System.out.println("开始制造华为手机: ");
Mate7 mate7 = director.buildMate7();
System.out.println(mate7);
Mx4Pro mx4Pro = director.buildMx4Pro();
System.out.println(mx4Pro);
}
}
Java
Copy
开始制造华为手机:
这是华为mate7手机
Mate7{cpu='采用华为自主研发的最先芯片', ram='4G内存', screen='6寸1080P分辨率60Hz', battery='3600毫安', facade='使用振金材料', other='屏下指纹识别'}
这是魅族MX4 Pro手机
Mx4Pro{cpu='采用魅族自主研发的最先芯片', ram='8G内存', screen='6寸4K分辨率144Hz', battery='4600毫安', facade='使用钛合金材料', other='侧边指纹识别'}
Process finished with exit code 0
原型模式
Prototype Pattern
现实场景
王小华用邮件的方式通知每一位同学, 类似于设计模式中的原型模式, 王小华以邮件为原型创建了N封邮件给每一位同学.
定义
用原型实例指定创建对象的种类, 并且通过复制这些原型创建新的对象.
角色
- 客户角色 : 改角色提出创建对象的请求.
- 抽象原型角色 : 该角色是一个抽象角色, 通常有一个java接口或者抽象类实现, 给出所有的具体原型所需的接口.
- 具体原型角色 : 该角色是被复制的对象, 必须实现抽象原型接口
java内置克隆机制
- 实现Cloneable 接口
- 覆盖Object的clone()方法, 完成对象的克隆操作, 通常只需要调用Object的clone()方法即可, 为了使外部能够调用此类的clone()方法, 可以将访问修饰符修改为public.
优点
- 性能优良, 原型模式是对内存二进制的拷贝, 要比直接new一个对象性能好, 特别当一个循环体内产生大量的对象时, 原型模式可以更好地体现其优点
- 避免构操函数 : 这既是优点也是缺点, 直接在内存中拷贝对象, 构造函数是不会被调用, 因此减少了约束, 不过这一点需要在实际应用时进行权衡考虑.
场景
- 资源优化场景, 类初始化时需要消耗非常多的资源, 这个资源包括数据, 硬件资源等.
- 性能和安全要求的场景, 如果通过new产生的一个对象需要非常繁琐的数据准备和访问安全, 则可以使用原型模式
- 一个对象多个修改者场景, 可以考虑使用原型模式拷贝多个多谢供调用者使用.
实例
package com.gylang.prototype;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class Mail implements Cloneable {
private String receive;
private String subject;
private String application;
private String context;
private String tail;
public Mail(String subject, String context) {
this.subject = subject;
this.context = context;
}
@Override
public Mail clone() {
try {
return (Mail) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
//set 和 get
public String getReceive() {
return receive;
}
public void setReceive(String receive) {
this.receive = receive;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getApplication() {
return application;
}
public void setApplication(String application) {
this.application = application;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public String getTail() {
return tail;
}
public void setTail(String tail) {
this.tail = tail;
}
}
Java
Copy
package com.gylang.prototype;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author gylang,
* @version 1.0
* @date 2020/1/4,
*/
public class SendMailDemo {
Map student = new LinkedHashMap();
public static void main(String[] args) {
Mail mail = new Mail("参加座谈会", "2014年12月12日,在121教室参加座谈会,每个人必须到场,不得迟到,当场点名");
mail.setTail("各位同学请相互转告. ");
SendMailDemo sendMailDemo = new SendMailDemo();
Map student = sendMailDemo.getStudent();
for (Object o : student.keySet()) {
Mail cloneMail = mail.clone();
cloneMail.setApplication(o.toString());
cloneMail.setReceive(student.get(o).toString());
sendMailDemo.sendMail(cloneMail);
}
}
public Map getStudent() {
student.put("王安", "wangan@gmail.com");
student.put("李华", "lihua@gmail.com");
student.put("李小刚", "lixoagang@gmail.com");
student.put("小郑", "xiaozheng@gmail.com");
student.put("小龙", "xiaolong@gmail.com");
student.put("小白", "xiaobai@gmail.com");
return student;
}
public void sendMail(Mail mail) {
System.out.println("标题:" + mail.getSubject() + "\t收件人: " + mail.getReceive()+
"\n正文: " + mail.getContext() +".....已发送");
}
}