1.单例设计模式:
/**
* 单例设计模式例子
* @author wx 2019-02-13
*/
public class SingleModel { //类一加载 就对象就已经存在
//饿汉式单例:弊端:类一加载 s 对象就一直占着内存,直到类被卸载时,静态变量才会被摧毁,释放内存。特定情况下会消耗内存
//三步
private static SingleModel s = new SingleModel();
private SingleModel() { } //私有构造
public static SingleModel getInstance() { //静态工厂方法
return s;
}
}
package designModelTest;
/**
* 懒汉式单例模式 (延迟加载方式)
* @author wx 2019-02-13
*弊端:多线程环境下会产生多个对象,使用同步锁可以避免
*/
/*public class SingleModel2 {
private static SingleModel2 s = null;
private SingleModel2(){}
public static SingleModel2 getInstance() {
if(s == null) {
s=new SingleModel2();
}
return s;
}
}*/
/**
* 使用同步代码块或对类使用同步锁
* 虽然解决了多个实例对象,但是效率低下,下一个对象想要使用对象,就必须等到上一个线程释放锁,才可以继续运行
* @author wx
*
*/
/*public class SingleModel2 {
private static SingleModel2 s = null;
private SingleModel2(){}
public static SingleModel2 getInstance() {
//等同于 synchronized public SingleModel2 getInstance() {}
synchronized(SingleModel2.class) {//同步代码块
if(s == null) {//这个判断一定要加 否则出现线程安全问题
s=new SingleModel2();
}
return s;
}
}
}*/
/**
* 使用DCL双检查锁机制,对上面代码进行优化
* 可以避免整个方法被锁,只需对锁的代码部分加锁,能提高执行效率
*/
public class SingleModel2 {
private static SingleModel2 s = null;
private SingleModel2(){}
public static SingleModel2 getInstance() {//只有调用此方法时,才会实例化对象
if(s == null) {
synchronized(SingleModel2.class) {//同步代码块
if(s == null) {//这个判断一定要加 否则出现线程安全问题
s=new SingleModel2();
}
}
}
return s;
}
}
2.模板方法模式:
基本思想:算法只存在一个地方,即父类中,容易修改。
实现方式:
a) 父类模板类(规定要执行的方法和顺序,只关心方法的定义及顺序
,不关心方法实现).
b) 子类实现类(实现a规定要执行的方法,只关心方法实现,不关心调用顺序)
/**
* 模板设计模式 模式--
* 解决问题;当功能内部一部分实现是确定,一部分实现是不确定的,这时可以把不确定的吧部分暴露出去,让子类去实现。
* @author wx 2019-02-20
*/
public abstract class TemplateModel {
public final void getTime() {//此功能不需要复写 ,可以加final 限定
long start =System.currentTimeMillis();
code();//不确定的部分 ,提取出来 ,通过抽象方法实现
long end=System.currentTimeMillis();
System.out.println("毫秒是:"+ (end-start));
}
public abstract void code();
}
public class TemplateModelImpl extends TemplateModel{
@Override
public void code() {
for (int i=0;i<100;i++) {//子类复写功能方法
System.out.println(i);
}
}
public void getAuthor() {
System.out.println("吴霞");
}
public class TemplateModelTest {
public static void main(String[] args) {
TemplateModel t = new TemplateModelImpl();
t.getTime();
//子类可以直接使用父类非抽象的方法
TemplateModelImpl t1 = new TemplateModelImpl();
t1.getTime();
}
}
}
模板模式之钩子方法
练习:
/**
* 2020-04-03 模板模式练习
* 重点:父类只负责定义顺序,不关心具体实现;子类做具体实现,不关系顺序
* 抽象类,表示豆浆
*/
public abstract class SoyaMilk {
//模板方法,可以做成final 不让子类去覆盖
final void make(){
select();
if (customerWantCondiments()){
addCondiments();
}
soak();
beat();
}
//选材料
void select(){
System.out.println("第一步:选好新鲜的黑豆...");
}
//添加不同的配料,抽象方法,让子类去实现
abstract void addCondiments();
//浸泡
void soak(){
System.out.println("第三步:黄豆和材料开始浸泡,浸泡三个小时....");
}
void beat(){
System.out.println("第四步:黄豆和配料放到豆浆机打碎...");
}
//钩子方法:定义一个方法,默认不做任何事情,子类视情况要不要覆盖它,则称该方法为钩子方法
boolean customerWantCondiments(){
return true;
}
}
public class PeanutBeanMilk extends SoyaMilk {
@Override
void addCondiments() {
System.out.println("加入上好的花生....");
}
}
public class PureSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
//空实现
}
@Override
boolean customerWantCondiments() {
return false;
}
}
/**
* 红豆豆浆
*/
public class RedBeanSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
System.out.println("加入好的红豆....");
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
//制作红豆豆浆
System.out.println("-------制作红豆豆浆------");
SoyaMilk redMilk = new RedBeanSoyaMilk();
redMilk.make();
System.out.println("-------制作花生豆浆------");
SoyaMilk peanutMilk = new PeanutBeanMilk();
peanutMilk.make();
System.out.println("-------制作纯豆浆------");
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
}
}
3.代理模式:
3.1.代理模式的定义:给某一个对象提供一个代理对象,并有代理对象控制原对象的引用。
代理模式类图代理模式类图
3.2.为什么要有代理模式:
a.中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
b.开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
3.3.代理模式的类型:
a.静态代理:
i.首先业务类接口,代理类,业务类,客户类
/**
* @author WX
* 定义一个账户接口
*/
public interface Account {
public List queryAccount(Long id);
public void updateAccount(Long id);
}
/**
* @author WX
* 业务实现类 (委托类),包含业务逻辑
*/
public class AcountImpl implements Account{
public List queryAccount(Long id) {
System.out.println("查看用户.....");
return null;
}
public void updateAccount(Long id) {
System.out.println("修改账户...");
}
}
ii.代理类和业务类(委托类)实现同一个接口,代理类中要组合业务类对象(以参数的形式加入到代理类的构造方法中)。代理类中和业务类同名的方法中,在调用真正业务方法之前,可以加入预处理操作,在调用真正业务方法之后,可以加入调用后的操作。
/**
* 账户代理类 :实现 委托类实现的接口,注入(构造器注入)委托类对象,通过委托类对象去调用真正的业务逻辑方法。
* @author WX
*/
public class AccountProxy implements Account {
private AcountImpl accountImpl;//组合一个业务实现类对象进行真正的业务方法的调用
public AccountProxy(AcountImpl acountImpl){
this.accountImpl=acountImpl;
}
public List queryAccount(Long id) {
System.out.println("查询账户得预处理——————————");
//调用真正的查询账户得方法
accountImpl.queryAccount(id);
System.out.println("查询账户之后——————————");
return null;
}
public void updateAccount(Long id) {
System.out.println("更新账户得预处理——————————");
//调用真正的更新账户得方法
accountImpl.updateAccount(id);
System.out.println("更新账户之后——————————");
}
}
iii.客户类:创建业务对象,代理对象。通过代理对象调用和业务类同名的方法,实现代理模式。
/**
* 模拟 account 类的调用方
* 静态代理的测试
* @author WX
*/
public class AccountClient {
public static void main(String[] args) {
//创建业务实现类对象,即委托类
AcountImpl accountImpl =new AcountImpl();
//创建代理类对象,通过构建参数的方式,将委托类对象传给代理类对象
AccountProxy accProxy=new AccountProxy(accountImpl);
accProxy.queryAccount(1L);
accProxy.updateAccount(1L);
}
}
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。 如果业务类不一样,但实现的功能相同,就会有很多重复代码出现。
b.JDK动态代理:
在JDK动态代理中我们不再需要再手动的创建代理类,只需要编写一个动态处理器就可以了。真正的代理对象由JDK在运行时为我们动态的来创建。
i.创建业务接口类,业务类,动态处理器[是一个java类],客户类
/**
* 业务接口
* @author WX
*/
public interface BookFacade {
public void addBook();
public List queryBook(String name);
//public List queryBookByid();
}
//实现类
public class BookFacadeImpl implements BookFacade {
BookDaoImpl bookDaoImpl=new BookDaoImpl();
public void addBook() {
System.out.println("增加一本java图书方法.....");
}
public List queryBook(String name){
List list=bookDaoImpl.queryBooks("java");
System.out.println("增加一本java图书方法开始.....");
if(list.size()>0){
// Iterator遍历
for (Iterator it = list.iterator(); it.hasNext();)
{
Book book=(Book) it.next();System.out.println("======="+book.getId()+","+book.getBookName()+","+book.getAuthor()+"=======");
}
}
System.out.println("增加一本java图书方法结束.....");
return null;
}
public List queryBookByid(){
List list=bookDaoImpl.queryBooksByid(201801L);
System.out.println("查询一本js图书方法开始.....");
if(list.size()>0){
// Iterator遍历
for (Iterator it = list.iterator(); it.hasNext();)
{
Book book=(Book) it.next();System.out.println("======="+book.getId()+","+book.getBookName()+","+book.getAuthor()+"=======");
}
}
System.out.println("查询一本js图书方法结束.....");
return list;
}
}
ii.动态处理器[是一个java类]实现InvocationHandler接口
,重写invoke()
方法,再写一个.bind方法
,用来创建代理类并返回代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import interfaceImpl.BookFacadeImpl;
import interfaces.BookFacade;
/**
* JDK动态代理 :实现调用管理接口InvocationHandler 创建动态代理类
* @author WX
* 写死实现委托类实现的接口,就是静态代理
* public class BookFacadeProxy implements BookFacade {
*/
public class BookFacadeProxy implements InvocationHandler {
/*静态代理模式的处理方法
* private BookFacadeImpl bookFacadeImpl;
public BookFacadeProxy(BookFacadeImpl bookImpl){//构造方法
this.bookFacadeImpl=bookImpl;
}*/
private Object target;//具体的业务类对象,调用实际的业务逻辑方法
/**
* 绑定业务对象,并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target){
this.target=target;
//通过反射机制,创建一个代理类对象实例,并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法时调用真正的业务方法),接口,handler实现类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/**
* 包装调用方法:进行预处理,方法调用后处理
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Object result=null;
System.out.println("增加图书预处理操作——————————1");
//调用真正的业务方法
result=method.invoke(target, args);
System.out.println("增加图书调用后处理——————————4");
return result;
}
}
iii.在客户类中,创建业务接口对象,动态处理器对象。通过向上转型得到业务接口对象(a),然后通过这个对象(a),调用接口中的方法。
/**
* JDK动态代理测试类:
* 1.创建业务实现类(委托类)对象,代理类对象
* 2.定义接口引用(向上转型),并用代理对象.bind(业务实现对象)的返回值进行赋值
* 3.通过接口引用调用业务方法(接口引用真正指向的是一个绑定了业务类的代理类对象,所以通过接口方法名调用的是被代理的方法们)
* @author WX
*/
public class BookFacadeClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
BookFacadeImpl bookFacadeImpl=new BookFacadeImpl();
BookFacadeProxy proxy=new BookFacadeProxy();
BookFacade bookFacade=(BookFacade)proxy.bind(bookFacadeImpl);
//bookFacade.addBook();
bookFacade.queryBook("js-0");
}
}
动态代理实现方法二:
package com.wx.proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 创建代理工厂
* 方法二:
*/
public class ProxyFactory {
public Object target;//目标对象
public ProxyFactory(Object target){//注入目标对象
this.target=target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象开始");
Object result = method.invoke(target,args);
System.out.println("代理对象结束");
return result;
}
});
}
}
class ProxyFactoryDemo{
public static void main(String[] args) {
Animal animal = new Cat();
Animal proxyFactory = (Animal) new ProxyFactory(animal).getProxyInstance();
proxyFactory.speak();
}
}
总结:
优点:相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度;
缺点:始终无法摆脱仅支持interface代理的桎梏,如果业务实现类新增了业务接口中没有的方法,这个方法,无法被JDK动态代理。
底层原理:利用了反射原理
c.cglib动态代理:
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类
,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术
,其原理是通过字节码技术为一个类(委托类)创建子类
,并在子类中采用方法拦截的技术
拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承
,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
i.创建cglib代理类,客户类,导入cglib.xx.jar包,asm.xxx.jar包
/**
* CGLIB动态代理:
* 1.定义一个业务类,无需实现接口,实现也不影响
* @author WX
*/
public class UserImpl{
public void addUser() {
System.out.println("增加一个用户.....");
}
}
ii.cglib代理类实现MethodInterceptor接口,并在代理中,写genInstance方法(同.bind方法一样)
/**
* 2.实现MethodInterceptor方法代理接口(需要导入cglib jar包), 创建代理类
* @author WX
*/
public class UserProxyCglib implements MethodInterceptor{
private Object target;//业务对象,供代理方法中进行真正的业务方法调用
/**
* 相当于JDK动态代理中的绑定
* @param object
* @return
*/
public Object getInstance(Object target){
this.target=target;//给业务对象赋值
//创建加强器,用来创建动态代理类
Enhancer enhancer=new Enhancer();
//为加强器指定要代理的业务类(即为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());;
//设置回调:对于代理类上所有方法的调用,都会调用callback,而callback需要实现intercepter方法进行拦截
enhancer.setCallback(this);
//创建动态代理类对象并返回
return enhancer.create();
}
//实现回调方法
@Override
public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("增加用户预处理--------------");
//调用业务类(父类)方法
proxy.invokeSuper(obj, arg2);
System.out.println("增加用户调用后--------------");
return null;
}
}
iii.在客户类中,创建业务类和代理类对象
/**
* cglib 动态代理的测试:
* cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,
* 并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
* @author WX
*/
public class UserCglibClient {
public static void main(String[] args) {
/**
* 1.创建业务类和代理类对象,
* 2.然后通过 代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。
* 3.最后通过动态代理类对象进行方法调用。
*/
//创建业务类对象
UserImpl userImpl=new UserImpl();
//创建代理类对象
UserProxyCglib proxyCglib=new UserProxyCglib();
UserImpl userCglib= (UserImpl) proxyCglib.getInstance(userImpl);
userCglib.addUser();
}
}
遇到的问题:
为什么呢?
- cglib-3.3.0.jar 当引入这个jar包是会报错:Exception in thread “main” java.lang.NoClassDefFoundError: org/objectweb/asm/Type
- cglib-nodep-3.3.0.jar:改成这个jar包就好了
CGLIB代理总结:
优点:CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。
缺点:由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。对于final修饰的类,也不能进行代理,因为被final修饰的类,不能被继承。
底层原理:底层将方法全部存入一个数组中,通过数组索引直接进行方法调用
4.观察者模式:(天气预报设计方案)对象之间是多对一的依赖关系
观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
实现方式:
a) 角色抽象类(提供对观察者的添加,删除和通知功能)。
b) 角色具体类,实现a,维护一个c的集合(对角色抽象类的实现)。
c) 观察者抽象类(被角色通知后实现的方法)。
d) 观察者实现类,实现c(多个)。
注:JDK提供了对观察者模式的支持,使用Observable类和Observer接口
代码练习:
public interface Observer {
public void update(float temperature,float pressure,float humidity);
}
/**
* 2020-04-04
* 观察者模式 接口
*/
public interface Subject {
public void register(Observer o);
public void remove(Observer o);
public void notifyObserver();
}
package com.wx.observer.improve;
import java.util.ArrayList;
/**
* 该类是核心
* 含有观察者集合,使用ArrayList集合
* 含有CurrentCondition 对象
* 当有数据更新时,就主动调用含有CurrentCondition对象的update方法(含有display方法)
*/
public class WeatherData implements Subject {
private float temperature;
private float pressure;
private float humidity;
//观察者集合
private ArrayList<Observer>observers;
public WeatherData() {
this.observers = new ArrayList<Observer>();
}
public void dataChange(){
notifyObserver();
}
//当数据有更新时,就调用setData
public void setData(float temperature,float pressure,float humidity){
this.temperature=temperature;
this.pressure=pressure;
this.humidity=humidity;
//调用这个方法,推送给调用者
dataChange();
}
public float getTemperature() {
return temperature;
}
public void setTemperature(float temperature) {
this.temperature = temperature;
}
public float getPressure() {
return pressure;
}
public void setPressure(float pressure) {
this.pressure = pressure;
}
public float getHumidity() {
return humidity;
}
public void setHumidity(float humidity) {
this.humidity = humidity;
}
//注册一个观察者
@Override
public void register(Observer o) {
observers.add(o);
}
//移除一个观察者
@Override
public void remove(Observer o) {
if(observers.contains(o))
observers.remove(o);
}
//遍历所有的观察者,并通知
@Override
public void notifyObserver() {
for (int i=0;i<observers.size();i++){
observers.get(i).update(this.temperature,this.pressure,this.humidity);
}
}
}
package com.wx.observer.improve;
/**
* 2020-04-04
* 显示当前天气情况(可以理解为天气气象局自己的网站)
*/
public class CurrentCondition implements Observer{
private float temperature;
private float pressure;
private float humidity;
//更新天气情况,由WeatherData来调用,使用推送模式
public void update(float temperature,float pressure,float humidity){
this.temperature=temperature;
this.pressure=pressure;
this.humidity=humidity;
display();
}
//显示天气
public void display(){
System.out.println("***today mTemprature:"+temperature+"***");
System.out.println("***today pressure:"+pressure+"***");
System.out.println("***today humidity:"+humidity+"***");
}
}
package com.wx.observer.improve;
public class BaiduSite implements Observer {
private float temperature;
private float pressure;
private float humidity;
//更新天气情况,由WeatherData来调用,使用推送模式
public void update(float temperature,float pressure,float humidity){
this.temperature=temperature;
this.pressure=pressure;
this.humidity=humidity;
display();
}
//显示天气
public void display(){
System.out.println("***百度网站 气温:"+temperature+"***");
System.out.println("***百度网站 气压:"+pressure+"***");
System.out.println("***百度网站 湿度:"+humidity+"***");
}
}
package com.wx.observer.improve;
import java.util.Observable;
public class Client {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
//创建观察者
CurrentCondition currentCondition = new CurrentCondition();
BaiduSite baiduSite = new BaiduSite();
//注册到weatherdata
weatherData.register(currentCondition);
weatherData.register(baiduSite);
//测试
System.out.println("通知各个注册的观察者");
weatherData.setData(10f,100f,33f);
//移除一个
System.out.println("=====================");
weatherData.remove(baiduSite);
System.out.println("通知各个注册的观察者");
weatherData.setData(10f,100f,33f);
//Observable 是类,不是接口,类中已经实现了核心方法。jdk中实现了Observable
}
}
5.策略模式:
实现方式:
a) 提供公共接口或抽象类,定义需要使用的策略方法。(策略抽象类)
b) 多个实现的策略抽象类的实现类。(策略实现类)
c) 环境类,对多个实现类的封装,提供接口类型的成员量,可以在客户端中切换。
d) 客户端 调用环境类 进行不同策略的切换。
注:Jdk中的TreeSet和 TreeMap的排序功能就是使用了策略模式。
6.简单工厂模式:
就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
实现方式:
a) 抽象产品类(也可以是接口)
b) 多个具体的产品类
c) 工厂类(包括创建a的实例的方法)
7.适配器模式:
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
7.1. 类适配器(子类继承方式)
实现方式:
a) 目标抽象角色(定义客户要用的接口)
b) 适配器(实现a继承c,作为一个转换器被客户调用)
c) 待适配器(真正需要被调用的)
d) 客户端(借用a的实例调用c的方法)
7.2. 对象适配器(对象的组合方式)
实现方式:
a) 目标抽象角色(定义客户要用的接口)
b) 适配器(实现a,维护一个c的引用,作为一个转换器被d调用)
c) 待适配器(真正需要被调用的)
d) 客户端(此类,借用a类的实例调用c类的方法,类似静态代理,但是解决的问题不同)
7.3. 缺省的方式
实现方式:
a) 抽象接口
b) 实现a的适配器类(空实现)
c) 客户端,继承b,调用b中的方法,不必直接实现a(直接实现a需要实现a中的所有的方法)
8.装饰模式:
实现方式:
a) 抽象的被装饰角色 (所有的角色都要直接或间接的实现本角色)
b) 具体的被装饰角色,实现或继承a (被功能扩展的角色)
c) 装饰角色,实现或继承a (本类有对a的引用,所有的具体装饰角色都需要继承这个角色)
d) 多个具体修饰角色 ,继承c(对被装饰角色的功能扩展,可以任意搭配使用)
9.迭代器模式:
如果集合元素,是用不同的方式实现的,有数组,java集合类(list,map),或其他方式,当客户端要遍历这些集合元素时,要使用多种遍历方式,而且还会暴露元素的内部结构,这种请款下可以考虑迭代器模式。
迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历元素
,不需要知道集合对象的底层表示,即:不暴露其内部结构
。
思想:管理对象集合和遍历对象集合分开(运用了单一职责原则)
在jdk集合中都运用了这种模式:ArrayList,LinkedList
代码练习:
/**
* 接口 ,核心
*/
public interface College {
public String getName();
//增加系的方法
public void addDepartment(String name,String desc);
//返回一个迭代器,遍历
public Iterator createIterator();
}
**
* 计算机学院
*/
public class ComputerCollege implements College {
Department[] departments;
int numOfDepartment = 0;//保存当前数组的对象个数
public ComputerCollege() {
departments = new Department[5];//假如最多只能放5个元素。初始化
addDepartment("java专业","java专业");
addDepartment("PHP专业","PHP专业");
addDepartment("大数据专业","大数据专业");
addDepartment("C++专业","C++专业");
}
@Override
public String getName() {
return "计算机学院";
}
//真正的数据是在这里加入的
@Override
public void addDepartment(String name, String desc) {
Department department =new Department(name,desc);
departments[numOfDepartment]=department;//因为是数组,要指定加的位置
numOfDepartment +=1;//表示已经加了一个系
}
//返回一个迭代器
@Override
public Iterator createIterator() {
return new ComputerCollegeIterator(departments);//要把departments 传进去,迭代器才知道怎么遍历
}
}
/**
* 2020-04-05 信息学院
*/
public class InfoCollege implements College {
List<Department> departmentList;//以list形式存放系
public InfoCollege() {
departmentList = new ArrayList<Department>();
addDepartment("信息安全系","信息安全系");
addDepartment("网络安全系","网络安全系");
addDepartment("服务器安全系","服务器安全系");
}
@Override
public String getName() {
return "信息工程学院";
}
//真正添加数据的地方
@Override
public void addDepartment(String name, String desc) {
Department department = new Department(name, desc);
departmentList.add(department);
}
//返回迭代器
@Override
public Iterator createIterator() {
return new InfoCollegeIterator(departmentList);
}
}
/**
* 系
*/
public class Department {
private String name;
private String desc;
public Department(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
/**
* 2020-04-05 计算机学院迭代器
*/
public class ComputerCollegeIterator implements Iterator {
//我们需要知道department 是以怎样的方式存储
Department[] departments;//计算机学院以数组的方式存放系
int position =0;//遍历的位置
public ComputerCollegeIterator(Department[] departments) {//注入数组数据
this.departments = departments;
}
@Override
public boolean hasNext() {
if(position >= departments.length || departments[position] == null){
return false;
}
return true;
}
@Override
public Object next() {
Department department = departments[position];
position +=position+1;
return department;
}
public void remove(){ }
}
/**
* 2020-04-05
* 信息工程学院迭代器
*/
public class InfoCollegeIterator implements Iterator {
List<Department> departmentList;//信息工程学院以List方式存放系
int index =-1;
public InfoCollegeIterator(List<Department> departmentList) {//注入集合数据
this.departmentList = departmentList;
}
//判断list集合中有没有下一个元素
@Override
public boolean hasNext() {
if(index >= departmentList.size() -1){
return false;
}else{
index +=1;
return true;
}
}
@Override
public Object next() {
return departmentList.get(index);
}
//空实现remove方法
@Override
public void remove() { }
}
/**
* 输出类
*/
public class OutputImpl {
//学院集合
List<College> collegeList;
public OutputImpl(List<College> collegeList) {//注入学院集合
this.collegeList = collegeList;
}
//遍历所偶的学院,然后调用printDepartment,然后输出各个学院的系
public void printCollege(){
//从collegeList取出所有的学院
Iterator<College> collegeIterator = collegeList.iterator();
while (collegeIterator.hasNext()){
//取出一个学院
College college = collegeIterator.next();
System.out.println("=========="+college.getName()+"==========");
printDepartment(college.createIterator());//得到对应的迭代器
}
}
//输出 :学院输出系
public void printDepartment(Iterator iterator){//给个迭代器,才能遍历
while(iterator.hasNext()){
Department department = (Department) iterator.next();//不管存储方式时数组,还是list
System.out.println(department.getName());
}
}
}
/**
*客户端调用
*/
public class Client {
public static void main(String[] args) {
//创建学院
List<College> collegeList = new ArrayList<College>();
ComputerCollege computerCollege= new ComputerCollege();
InfoCollege infoCollege = new InfoCollege();
collegeList.add(computerCollege);
collegeList.add(infoCollege);
//输出
OutputImpl output = new OutputImpl(collegeList);
output.printCollege();
}
}