1.面向对象的三大特性

1)封装(Encapsulation)

隐藏对象的具体实现细节,通过共有方法暴露对象的功能。内部结构可以自由修改,同时可对成员进行更加精确的控制 (比如在setter方法中加值合法判断)

2)继承(Inheritance)

使用已经存在的类作为基础类(父类),在此基础上建立新类(子类), 子类既可复用父类的功能,也能进行扩展,从而实现代码复用。 另外,Java不能像C++那样同时继承多个父类,只能树形的继承, 比如:Man -> Human -> Animal,或通过接口和内部类实现多继承。

另外,关于继承还需注意以下几点:

  • 1.子类拥有父类非private的属性与方法
  • 2.构造方法只能调用,不能实现,子类默认调用父类的无参构造方法,
    如果父类没有无参的构造方法,需要使用super显式调用!
  • 3.慎用继承,要考虑是否需要从子类向父类进行向上转型!

3)多态(Polymorphism)

定义:一个类实例的相同方法在不同的情形下有不同的表现形式

分为以下两种:

  • 编译时多态(OverLoading)—— 方法重载
  • 运行时多态(OverRidding)—— 继承 + 方法重写 + 向上转型(父类引用指向子类对象)

运行时多态(动态绑定,new后面什么类型,动态类型就是什么类型)

示例如下:

C++代码
  1. class?Animal()?{?fun?show()?{?println("动物")?}}??
  2. class?People:Animal()?{?fun?show()?{?println("人类")?}}??
  3. //下述代码打印结果:人类??
  4. Animal?animal?=?new?People()??
  5. animal.show()

2.类与类间的关系

口诀鸡湿衣冠剧组(继承,实现,依赖,关联,聚合,组合)

继承和实现就不说了,后面四个只是 语意层次 的区别
两个类的相关程度,依赖 < 关联 < 聚合 < 组合

依次的UML类图标记:

  • 继承/泛化(Generalization): 子类 父类

  • 实现(Realization):实现类 接口

  • 依赖(Dependency):不持有引用,具体表现:局部变量,函数参数,
    返回值使用 依赖类,比如大佬依赖于递茶小弟;

  • 关联(Association):持有引用,具体表现:成员变量, 箭头指向被关联类,可双向,一对多或多对多:

  • 聚合(Aggregation):成员变量,关联是处于同一层次的,而聚合则 是整体和局部层次的,比如:社团小弟,另外即使没有了社团, 小弟们依旧可以到别的地方搞事情。

  • 组合(Composition):与聚合类似,程度更加强烈,共生死,组合类 负责被组合类的生命周期,比如: 社团大佬,如果没了社团, 大佬也就就不能存在了。


3.面向对象七大原则

  • 单一职责原则(Single Responsibility Principle)
    每一个类应该专注于做一件事情。 即:高内聚,低耦合。

  • 开闭原则(Open Close Principle)
    一个对象对扩展开放对修改关闭。即:对类的改动是通过增加代码进行的,而不是修改现有代码。

  • 里氏替换原则(Liskov Substitution Principle)
    在任何父类出现的地方都可以用它的子类来替代。

  • 依赖倒置原则(Dependence Inversion Principle)
    要依赖于抽象不要依赖于具体实现

  • 接口隔离原则(Interface Segregation Principle)
    应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

  • 迪米特原则(Law Of Demeter)
    一个对象应当尽量少地与其他对象之间发生相互作用,使得系统功能模块相对独立。

  • 组合/聚合复用原则(Composite/Aggregate Reuse Principle)
    尽量使用组合/聚合的方式,而不是使用继承


23种设计模式

  • 创建型(5种):主要用于处理对象的创建,实例化对象:
    单例建造者原型工厂方法抽象工厂

  • 结构型(7种):处理类或对象间的组合
    适配器装饰者结合桥接外观享元代理

  • 行为型(11种):描述类或对象怎样进行交互和职责分配
    策略观察者迭代器命令备忘录中介者解释器访问者责任链状态模板方法


一. 单例模式(Singleton Pattern)

作用:保证 类在内存中对象唯一性

适用场景

  • 1.避免创建多个实例浪费资源
  • 2.避免多个实例因多次调用而出现错误
  • 3.一般写工具类,线程池,缓存,数据库会用到。

套路(三个要点):

  • 1.不允许在类外new对象 —— 构造方法私有化
  • 2.在类中创建对象 —— 通过new在本类中创建一个实例
  • 3.对外提供获取该实例的方法 —— 定义公有方法返回创建的实例

饿汉与懒汉的区别

前者在类装载时就实例化,后者只有在第一次被使用时才实例化。 (饿汉的优点是避免线程同步问题,缺点是即使没用到这个实例还是会加载) (懒汉的优点是实现了懒加载,但需要解决线程安全问题!)

7种单例套路

1)饿汉式,没有实现懒加载~

Java代码
  1. public?class?Singleton()?{??
  2. ????private?static?Singleton?instance?=?new?Singleton();??
  3. ????private?Singleton(){?}??
  4. ????public?static?Singleton?getInstance()?{???
  5. ????????return?instance;????
  6. ????}??
  7. }??
  8. //获取单例对象??
  9. Singleton?mSingleton?=?Singleton.getInstance();

2)懒汉式

虽然达到了懒加载,但是却存在线程安全问题,比如有两个线程都刚好执行完if(instance == null),接着准备执行instance = new Singleton() 语句,这样的结果会导致我们实例化了两个Singleton对象,为了解决线程不安全问题,可以对getInstance()方法加锁。

Java代码
  1. public?class?Singleton?{??
  2. ????private?static?Singleton?instance?=?null;??
  3. ????private?Singleton()?{?}??
  4. ????private?static?Singleton?getInstance()?{??
  5. ????????if(instance?==?null)?{???
  6. ????????????instance?=?new?Singleton();???
  7. ????????}??
  8. ????????return?instance;??
  9. ????}??
  10. }

3)懒汉式加锁版

为getInstance方法加锁虽然保证了线程安全,但是每次执行getInstance() 都需要同步,而实例化对象只需要执行一次就够了,后面获取该示例, 应该直接return就好了,方法同步效率太低,一种改进后的写法是: synchronized (Singleton.class) { instance = new Singleton(); } 但是,这样写依然是线程不安全的,如果你还是想用懒汉式的话,推荐双重检查锁定(DCL,Double Check Lock)。

Java代码
  1. public?class?Singleton?{??
  2. ????private?static?Singleton?instance?=?null;??
  3. ????private?Singleton()?{?}??
  4. ????private?static?synchronized?Singleton?getInstance()?{??
  5. ????????if(instance?==?null)?{???
  6. ????????????instance?=?new?Singleton();???
  7. ????????}??
  8. ????????return?instance;??
  9. ????}??
  10. }

4)懒汉式双重校验锁(DCL)

代码中进行了两次if检查,这样就可以保证线程安全,初始化一次后,后面再次访问时,if检查,直接return 实例化对象。volatile是1.5后引入的,volatile关键字会屏蔽Java虚拟机所做的一些代码优化,会导
致系统运行效率降低,而更好的写法是使用静态内部类来实现单例!

Java代码
  1. public?class?Singleton{??
  2. ????private?static?volatile?Singleton?instance?=?null;??
  3. ????private?Singleton()?{?}??
  4. ????public?static?Singleton?getInstance()?{??
  5. ????????if(instance?==?null)?{??
  6. ????????????synchronized(Singleton.class)?{??
  7. ????????????????if(instance?==?null)?instance?=?new?Singleton();??
  8. ????????????}??
  9. ????????}??
  10. ????????return?instance;??
  11. ????}??
  12. ?}

5)静态内部类实现单例(推荐)

和饿汉式类似,都是通过类加载机制来保证初始化实例的时候只有一个线程,从而避免线程安全问题,饿汉式的Singleton类被加载时,就会实例化,而静态内部类这种,当Singleton类被加载时,不会立即实例化,调用getInstance() 方法才会装载SingletonHolder类,从而完成Singleton的实例化。

Java代码
  1. public?class?Singleton?{??
  2. ????private?Singleton()?{?}??
  3. ????private?static?final?Singleton?getInstance()?{??
  4. ????????return?SingletonHolder.INSTANCE;??
  5. ????}??
  6. ????private?static?class?SingletonHolder?{??
  7. ????????private?static?final?Singleton?INSTANCE?=?new?Singleton()??
  8. ????}??
  9. }

6)枚举实现单例

INSTANCE即为SingletonEnum类型的引用,得到它就可以调用
枚举中的方法。既避免了线程安全问题,还能防止反序列化
重新创建新的对象,但是失去了类的一些特性,而且没有延时加载。

Java代码
  1. public?enum?SingletonEnum?{??
  2. ????INSTANCE;??
  3. ????private?Singleton?instance;??
  4. ????SingletonEnum()?{???
  5. ????????instance?=?new?Singleton();??
  6. ????}??
  7. ????public?Singleton?getInstance()?{???
  8. ????????return?instance;???
  9. ????}??
  10. }??
  11. //调用方式??
  12. SingletonEnum.INSTANCE.method();?

7)容器实现单例

将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象
对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使
用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用
户隐藏了具体实现,降低了耦合度。

Java代码
  1. public?class?SingletonManager?{??
  2. ????private?static?Map?objMap?=?new?HashMap();??
  3. ????private?Singleton(){?}??
  4. ????public?static?void?registerService(String?key,Object?instance)?{??
  5. ????????if(!objMap.containsKey(key))?{??
  6. ????????????objMap.put(key,instance);??
  7. ????????}??
  8. ????}??
  9. ????public?static?Object?getService(String?key)?{??
  10. ????????return?objMap.get(key);??
  11. ????}??
  12. }

二. 建造者模式(Builder Pattern)

复杂对象的构建与表示分离 开来,使得同样的构建过程可以创建不同的表示,缺点是可能产生多余的创建者与构建过程对象,消耗内存,不适用于内部建造顺序不稳定,变化复杂的对象,可能导致需要创建很多具体的建造者来实现这些变化。

例子:玩游戏创建角色时的自定义,不同的搭配生成不同的角色。

四个角色与UML类图

示例代码

Java代码
  1. //产品类??
  2. class?Character?{??
  3. ????private?String?sex;??
  4. ????private?String?face;??
  5. ????private?String?clothes;??
  6. ??
  7. ????void?setSex(String?sex)?{?this.sex?=?sex;}??
  8. ????void?setFace(String?face)?{?this.face?=?face;?}??
  9. ????void?setClothes(String?clothes)?{?this.clothes?=?clothes;}??
  10. ??
  11. ????String?showMsg()?{?return?"你创建了一个穿着?"?+?clothes?+?"?一副?"?+?face?+?"?的"?+?sex?+?"ヾ(≧▽≦*)o?戳菊狂笑~";?}??
  12. }??
  13. ??
  14. //抽象Builder接口??
  15. interface?Builder?{??
  16. ????void?setSex(String?sex);??
  17. ????void?setFace(String?face);??
  18. ????void?setClothes(String?clothes);??
  19. ????Character?build();??
  20. }??
  21. ??
  22. //Builder接口实现类??
  23. class?ConcreteBuilder?implements?Builder?{??
  24. ????private?Character?mCharacter?=?new?Character();??
  25. ??
  26. ????@Override?public?void?setSex(String?sex)?{?mCharacter.setSex(sex);?}??
  27. ????@Override?public?void?setFace(String?face)?{?mCharacter.setFace(face);?}??
  28. ????@Override?public?void?setClothes(String?clothes)?{?mCharacter.setClothes(clothes);?}??
  29. ????@Override?public?Character?build()?{return?mCharacter;}??
  30. }??
  31. ??
  32. //装配过程类??
  33. class?Director?{??
  34. ????private?Builder?mBuilder?=?null;??
  35. ????Director(Builder?builder)?{?this.mBuilder?=?builder;?}??
  36. ????Character?createCharacter(String?sex,?String?face,?String?clothes)?{??
  37. ????????this.mBuilder.setSex(sex);??
  38. ????????this.mBuilder.setFace(face);??
  39. ????????this.mBuilder.setClothes(clothes);??
  40. ????????return?mBuilder.build();??
  41. ????}??
  42. }??
  43. ??
  44. //客户端调用类??
  45. public?class?Game?{??
  46. ????public?static?void?main(String[]?args)?{??
  47. ????????Builder?builder?=?new?ConcreteBuilder();??
  48. ????????Director?director?=?new?Director(builder);??
  49. ????????Character?character?=??director.createCharacter("基佬","硬汉脸","死库水");??
  50. ????????System.out.println(character.showMsg());??
  51. ????}??
  52. }

输出结果


三. 原型模式(Prototype Pattern)

下面两种场景可以考虑使用原型模式:

  • 1.当初始化类对象需要消耗非常多资源,或者说要进行繁琐
    的数据准备或者权限,如果想简化创建,可以使用原型模式。
  • 2.一个对象提供给其他对象访问,而各个调用者可能都需要
    修改对象的值,可以考虑使用原型模式克隆多个对象供调用者
    使用(保护性拷贝

三个角色与UML类图

Java中 == 与equals的区别

  • ==基本数据类型(int,long等),比较存储的值是否相等
    对比的是引用类型,比较的是所指对象地址是否相等

  • equals,不能用于比较基本数据类型,如果**没对equals()方法进行重写,比较的是指向的对象地址,如果想要比较对象内容,需要自行重写**方法,做相应的判断!!!!String调equals是可以判断内容是否一样,是因为对equals()方法进行了重写,具体可参见源码!

克隆需要满足的三个条件

  • 1.x.clone()!=x ,即 不是同一对象
  • 2.x.clone().getClass == x.getClass(),即 对象类型一致
  • 3.如果对象obj的equals()方法定义恰当的话,那么
    obj.clone().equals(obj) == true应当是成立的。(推荐,不强制)

Java中如何使用

Prototype原型类(想被克隆的类)实现Cloneable接口重写clone()方法。

Java代码
  1. ConcretePrototype?cp1?=?new?ConcretePrototype();???
  2. ConcretePrototype?cp2?=?(ConcretePrototype)cp1.clone();?

需注意

  • 1.执行克隆方法,不会调用构造方法
  • 2.克隆会生成的新的对象成员,但指向的却是同一个内存地址
  • 3.克隆前后数据类型一致
  • 4.克隆的时候,类中基本数据类型的属性会新建,但是引用类型
    只会生成个新的引用变量,引用变量的地址依旧指向同一个内存地址!

实现深拷贝的两种套路

这种只新建基本类型数据,不新建引用类型数据,称为浅拷贝,如果连引用类型数据也新建的话,则称为深拷贝

两个套路:

1.引用类型也实现Cloneable接口,如果属性的类型也是对象,那么需要一直递归的克隆下去
2.序列化,属性的类型是引用类型的话,需要实现Serializable接口,然后自己写个方法来在里面**完成对象转二进制流与二进制流转对象**的方法,然后返回克隆后的对象!

具体代码见:3.Prototype Pattern


四.工厂方法模式(Factory Method Pattern)

关于三种工厂模式,其实理解起来非常简单,只是把对象的创建放到一个特定的类中,相比起我们直接new对象,这种套路会写多几个类,但是却拥有更好的扩展性,而且当创建的对象发生改变,可以减少一定的修改量。(想想你在项目中有一个类在多处都new了,现在需要对这个类的构造方法,或者相关参数做些修改,你需要找到每个new这个类的地方进行修改,而如果你把工作都丢给一个工厂类,你可能只需要修改这个类) 另外,简介下这几种工厂模式的区别:

  • 简单工厂模式:最简单的直接把new对象丢到一个工厂类中;
  • 工厂方法模式:对工厂类进行抽象,实现具体工厂类以创建不同对象;
  • 抽象工厂模式:当工厂需要创建多种相互关联或依赖的对象,有两个名
    产品等级结构产品族,具体是什么的自己看~

简单工厂模式的三个角色

代码示例

Java代码
  1. abstract?class?Tea?{??
  2. ????public?abstract?void?加奶茶();??
  3. ????public?abstract?void?加料();??
  4. }??
  5. ??
  6. class?YeGuoTea?extends?Tea{??
  7. ????@Override?public?void?加奶茶()?{?System.out.println("加了一把奶茶");}??
  8. ????@Override?public?void?加料()?{System.out.println("加了一把椰果");}??
  9. }??
  10. ??
  11. class?ZhenZhuTea??extends?Tea{??
  12. ????@Override?public?void?加奶茶()?{?System.out.println("加了一把奶茶");}??
  13. ????@Override?public?void?加料()?{System.out.println("加了一把珍珠");}??
  14. }??
  15. ??
  16. public?class?Me?{??
  17. ????public?static?Tea?makeTea(int?type)?{??
  18. ????????System.out.println("==============");??
  19. ????????Tea?tea?=?type?==?0???new?ZhenZhuTea()?:?new?YeGuoTea();??
  20. ????????tea.加奶茶();??
  21. ????????tea.加料();??
  22. ????????return?tea;??
  23. ????}??
  24. }??
  25. ??
  26. public?class?Store?{??
  27. ????public?static?void?main(String[]?args)?{??
  28. ????????for?(int?i?=?0;i?3;i++)?{??
  29. ????????????Tea?tea?=?Me.makeTea(buyTea());?//小猪制作奶茶??
  30. ????????}??
  31. ????}??
  32. ??
  33. ????/*?模拟用户下单,0代表要珍珠奶茶,1代表要椰果奶茶?*/??
  34. ????private?static?int?buyTea()?{??
  35. ????????return?new?Random().nextInt(2);??
  36. ????}??
  37. }?

输出结果


工厂方法模式(静态工厂)

其实就是在简单工厂模式基础上,把工厂创建不同产品的内部逻辑抽取出来,生成一个抽象工厂,再创建具体工厂类,生产不同的产品。

UML类图

代码示例

Java代码
  1. //工厂接口/抽象类??
  2. abstract?class?MakeTea?{??
  3. ????abstract?Tea?小猪带特效的奶茶制作工艺();??
  4. }??
  5. ??
  6. //工厂实现类1??
  7. class?ZhenZhuMakeTea?extends?MakeTea?{??
  8. ????@Override??
  9. ????Tea?小猪带特效的奶茶制作工艺()?{??
  10. ????????System.out.println("======?珍珠小弟炮制港式珍珠奶茶?======");??
  11. ????????Tea?tea?=?new?ZhenZhuTea();??
  12. ????????tea.加奶();??
  13. ????????tea.加茶();??
  14. ????????tea.加料();??
  15. ????????tea.打包();??
  16. ????????return?tea;??
  17. ????}??
  18. }??
  19. ??
  20. //工厂实现类2??
  21. class?YeGuoMakeTea?extends?MakeTea?{??
  22. ????@Override??
  23. ????Tea?小猪带特效的奶茶制作工艺()?{??
  24. ????????System.out.println("======?椰果小弟炮制日式椰果奶茶?======");??
  25. ????????Tea?tea?=?new?YeGuoTea();??
  26. ????????tea.加奶();??
  27. ????????tea.加茶();??
  28. ????????tea.加料();??
  29. ????????tea.打包();??
  30. ????????return?tea;??
  31. ????}??
  32. }??
  33. ??
  34. //客户端调用??
  35. public?class?StoreS?{??
  36. ????public?static?void?main(String[]?args)?{??
  37. ????????//初始化两个小弟??
  38. ????????ZhenZhuMakeTea?zhenzhu?=?new?ZhenZhuMakeTea();??
  39. ????????YeGuoMakeTea?yeguo?=?new?YeGuoMakeTea();??
  40. ??
  41. ????????for?(int?i?=?0;i?3;i++)?{??
  42. ????????????Tea?tea?=?buyTea()?==?0???zhenzhu.小猪带特效的奶茶制作工艺()???
  43. ????????????????:?yeguo.小猪带特效的奶茶制作工艺();??
  44. ????????}??
  45. ????}??
  46. ??
  47. ????/*?模拟用户下单,0代表要珍珠奶茶,1代表要椰果奶茶?*/??
  48. ????private?static?int?buyTea()?{??
  49. ????????return?new?Random().nextInt(2);??
  50. ????}??
  51. }?

输出结果

另外还可以通过反射简洁生产过程,直接传入产品的类类型,生成对应的产品,示例如下:

Java代码
  1. abstract?class?SMakeTea?{??
  2. ????public?abstract?<>extends?Tea>?T?小猪带特效的奶茶制作工艺(Class?clz);??
  3. }??
  4. ??
  5. class?SMe?extends?SMakeTea?{??
  6. ????@Override??
  7. ????public?<>extends?Tea>?T?小猪带特效的奶茶制作工艺(Class?clz)?{??
  8. ????????System.out.println("==============");??
  9. ????????Tea?tea?=?null;??
  10. ????????try?{??
  11. ????????????tea?=?(Tea)?Class.forName(clz.getName()).newInstance();??
  12. ????????????tea.加奶();??
  13. ????????????tea.加茶();??
  14. ????????????tea.加料();??
  15. ????????????tea.打包();??
  16. ????????}?catch?(Exception?e)?{??
  17. ????????????e.printStackTrace();??
  18. ????????}??
  19. ????????return?(T)?tea;??
  20. ????}??
  21. }??
  22. ??
  23. public?class?SStore?{??
  24. ????public?static?void?main(String[]?args)?{??
  25. ????????SMe?me?=?new?SMe();??
  26. ????????me.小猪带特效的奶茶制作工艺(ZhenZhuTea.class);??
  27. ????????me.小猪带特效的奶茶制作工艺(YeGuoTea.class);??
  28. ????}??
  29. }

六. 抽象工厂模式(Abstract Factory Pattern)

代码示例

Java代码
  1. //抽象产品类1??
  2. abstract?class?Drink?{??
  3. ????public?abstract?void?drink();??
  4. }??
  5. ??
  6. //抽象产品类2??
  7. abstract?class?Snack?{??
  8. ????public?abstract?void?snack();??
  9. }??
  10. ??
  11. //具体产品类们??
  12. class?MilkTea?extends?Drink?{??
  13. ????@Override?public?void?drink()?{?System.out.println("一杯奶茶");?}??
  14. }??
  15. ??
  16. class?Juice?extends?Drink?{??
  17. ????@Override?public?void?drink()?{?System.out.println("一杯果汁");?}??
  18. }??
  19. ??
  20. class?HandGrab?extends?Snack?{??
  21. ????@Override?public?void?snack()?{?System.out.println("一个手抓饼");?}??
  22. }??
  23. ??
  24. class?FishBall?extends?Snack?{??
  25. ????@Override?public?void?snack()?{?System.out.println("一碗鱼蛋");?}??
  26. }??
  27. ??
  28. //抽象工厂类??
  29. abstract?class?MakeFood?{??
  30. ????abstract?Drink?createMakeDrink();??
  31. ????abstract?Snack?createMakeSnack();??
  32. }??
  33. ??
  34. //具体工厂类1??
  35. class?FirstXiaoDi?extends?MakeFood?{??
  36. ????@Override?public?Drink?createMakeDrink()?{?return?new?MilkTea();?}??
  37. ????@Override?public?Snack?createMakeSnack()?{?return?new?HandGrab();?}??
  38. }??
  39. ??
  40. //具体工厂类2??
  41. class?SecondXiaoDi?extends?MakeFood?{??
  42. ????@Override?public?Drink?createMakeDrink()?{?return?new?Juice();?}??
  43. ????@Override?public?Snack?createMakeSnack()?{?return?new?FishBall();?}??
  44. }??
  45. ??
  46. //客户端调用??
  47. public?class?Store?{??
  48. ????public?static?void?main(String[]?args)?{??
  49. ????????//初始化两个小弟??
  50. ????????MakeFood?xiaodi1?=?new?FirstXiaoDi();??
  51. ????????MakeFood?xiaodi2?=?new?SecondXiaoDi();??
  52. ??
  53. ????????for(int?i?=?0;i?4?;i++)?{??
  54. ????????????System.out.println("======?根据订单配餐:?======");??
  55. ????????????Drink?drink?=?buyDrink()?==?0????
  56. ????????????????xiaodi1.createMakeDrink()?:?xiaodi2.createMakeDrink();??
  57. ????????????Snack?snack?=?buySnack()?==?0?????
  58. ????????????????xiaodi1.createMakeSnack()?:?xiaodi2.createMakeSnack();??
  59. ????????????drink.drink();??
  60. ????????????snack.snack();??
  61. ????????}??
  62. ????}??
  63. ??
  64. ????/*?模拟用户点饮料,0代表要奶茶,1代表要果汁?*/??
  65. ????private?static?int?buyDrink()?{?return?new?Random().nextInt(2);?}??
  66. ??
  67. ????/*?模拟用户点小吃,0代表要手抓饼,1代表要鱼蛋?*/??
  68. ????private?static?int?buySnack()?{?return?new?Random().nextInt(2);?}??
  69. }

输出结果

两个名词(产品等级结构产品族)

  • 产品等级结构(继承)
    比如这里的抽象类是Drink(饮料),子类有奶茶,果汁,然后抽象饮料与具体饮料构成了一个产品等级结构,抽象饮料是父类,具体饮料是其子类。

  • 产品族
    同一工厂生产的,位于不同产品等级结构的一组产品,比如这里的奶茶和果汁属于饮料结构的一组产品,而手抓饼和鱼蛋则属于小吃结构的一组产品。

四个角色与UML类图

抽象工厂模式适用于创建的对象有多个相互关联或依赖的产品族;抽象工厂模式隔离具体类的生成,接口与实现分离,增加新的产品族很方便;但是扩展新的产品等级结构麻烦,需要修改抽象工厂,具体工厂类也要更改。


七. 适配器模式(Adapter Pattern)

两个彼此间没太大关联的类,想进行交互完成某些事情,不想直接去修改各自的接口,可以添加一个中间类,让他来协调两个类间的关系,完成相关业务,这种模式就叫适配器模式。

然后分为:类适配器对象适配器 两种,前者和适配者是继承关系,后者与适配者则是引用关系。

对象适配器支持传入一个被适配器对象,因此可以做到对多种被适配接口进行适配。而类适配器直接继承无法动态修改,所以一般情况下对象适配器使用得更多!(Java不支持多重继承!!!)

对象适配器例子(用得较多)

Java代码
  1. /*?目标接口?*/??
  2. interface?Chinese?{??
  3. ????void?speakChinese(String?string);??
  4. }??
  5. ??
  6. /*?需要适配的类?*/??
  7. class?English?{??
  8. ????void?speakEnglish(String?string)?{?System.out.println("【英语】"?+?string);?}??
  9. }??
  10. ??
  11. /*?适配器?*/??
  12. class?Translator?implements?Chinese{??
  13. ????private?English?english?=?new?English();??
  14. ??
  15. ????Translator(English?english)?{?this.english?=?english;?}??
  16. ??
  17. ????@Override?public?void?speakChinese(String?string)?{?english.speakEnglish(string);?}??
  18. }??
  19. ??
  20. /*?客户端调用?*/??
  21. public?class?Client?{??
  22. ????public?static?void?main(String[]?args)?{??
  23. ????????Chinese?chinese?=?new?Translator(new?English());??
  24. ????????chinese.speakChinese("那你很棒棒哦!");??
  25. ????}??
  26. }?

输出结果

类适配器例子

Java代码
  1. /*?类适配器?*/??
  2. class?ClassTranslator?extends?English?implements?Chinese?{??
  3. ????@Override?public?void?speakChinese(String?string)?{?speakEnglish(string);?}??
  4. }??
  5. ??
  6. /*?客户端调用?*/??
  7. public?class?ClientC?{??
  8. ????public?static?void?main(String[]?args)?{??
  9. ????????ClassTranslator?translator?=?new?ClassTranslator();??
  10. ????????translator.speakChinese("你也很好啊!");??
  11. ????}??
  12. }?

输出结果

除此之外还有个缺省适配器模式的名词,简单点说就是不需要实现接口中提供的所有方法时,先写一个抽象类实现这个接口,然后为每个方法提供一个默认实现(空方法),然后选择性覆盖某些方法实现需求,又称单接口适配器模式。


八.装饰者模式(Decorator Pattern)

动态的给对象添加一些额外的职责,就增加功能来说,装饰者模式比起生成子类更加灵活!就是想替代多重层继承的模式。其实就是一层套一层

代码示例

Java代码
  1. /*?抽象组件?*/??
  2. abstract?class?Tea?{??
  3. ????private?String?name?=?"茶";??
  4. ??
  5. ????public?String?getName()?{?return?name;?}??
  6. ??
  7. ????void?setName(String?name)?{?this.name?=?name;?}??
  8. ??
  9. ????public?abstract?int?price();??
  10. }??
  11. ??
  12. /*?具体组件?*/??
  13. class?MilkTea?extends?Tea?{??
  14. ????MilkTea()?{?setName("奶茶");?}??
  15. ??
  16. ????@Override?public?int?price()?{?return?5;?}??
  17. }??
  18. ??
  19. class?LemonTea?extends?Tea{??
  20. ????LemonTea()?{?setName("柠檬茶");?}??
  21. ??
  22. ????@Override?public?int?price()?{?return?3;?}??
  23. }??
  24. ??
  25. /*?抽象装饰类?*/??
  26. abstract?class?Decorator?extends?Tea{??
  27. ????public?abstract?String?getName();??
  28. }??
  29. ??
  30. /*?具体装饰类?*/??
  31. class?ZhenZhu?extends?Decorator?{??
  32. ????Tea?tea;??
  33. ??
  34. ????ZhenZhu(Tea?tea)?{?this.tea?=?tea;?}??
  35. ??
  36. ????@Override?public?String?getName()?{?return?"珍珠"?+?tea.getName();?}??
  37. ??
  38. ????@Override?public?int?price()?{?return?2?+?tea.price();?}??
  39. }??
  40. ??
  41. class?YeGuo?extends?Decorator{??
  42. ????//...??
  43. }??
  44. ??
  45. class?JinJu?extends?Decorator{??
  46. ????//...??
  47. }??
  48. ??
  49. class?HongDou?extends?Decorator{??
  50. ????//...??
  51. }??
  52. ??
  53. /*?客户端调用?*/??
  54. public?class?Store?{??
  55. ????public?static?void?main(String[]?args)?{??
  56. ????????Tea?tea1?=?new?MilkTea();??
  57. ????????System.out.println("你点的是:"?+?tea1.getName()?+?"?价格为:"?+?tea1.price());??
  58. ??
  59. ????????Tea?tea2?=?new?LemonTea();??
  60. ????????tea2?=?new?JinJu(tea2);??
  61. ????????System.out.println("你点的是:"?+?tea2.getName()?+?"?价格为:"?+?tea2.price());??
  62. ??
  63. ????????Tea?tea3?=?new?MilkTea();??
  64. ????????tea3?=?new?ZhenZhu(tea3);??
  65. ????????tea3?=?new?YeGuo(tea3);??
  66. ????????tea3?=?new?HongDou(tea3);??
  67. ????????tea3?=?new?JinJu(tea3);??
  68. ????????System.out.println("你点的是:"?+?tea3.getName()?+?"?价格为:"?+?tea3.price());??
  69. ????}??
  70. }

输出结果


九.组合模式(Composite Pattern)

部分-整体模式,把具有 相似的一组对象 当做一个对象处理,用一种 树状的结构组合对象,再提供统一的方法去访问相似的对象,以此忽略掉对象与对象容器间的差别。

根节点枝结点叶子结点 三个名词需要理解,类比上图,根节点是菜单,枝结点是饮料菜单和小吃菜单,叶子结点是奶茶,果汁,手抓饼和鱼蛋!

代码示例

Java代码
  1. /*?抽象组件?*/??
  2. abstract?class?AbstractMenu?{??
  3. ????public?abstract?void?add(AbstractMenu?menu);??
  4. ????public?abstract?AbstractMenu?get(int?index);??
  5. ????public?abstract?String?getString();??
  6. }??
  7. ??
  8. /*?容器组件?*/??
  9. class?Menu?extends?AbstractMenu?{??
  10. ????private?String?name;??
  11. ????private?String?desc;??
  12. ????private?List?menus?=?new?ArrayList<>();??
  13. ??
  14. ????Menu(String?name,?String?desc)?{??
  15. ????????this.name?=?name;??
  16. ????????this.desc?=?desc;??
  17. ????}??
  18. ??
  19. ????@Override?public?void?add(AbstractMenu?menu)?{?menus.add(menu);?}??
  20. ??
  21. ????@Override?public?AbstractMenu?get(int?index)?{?return?menus.get(index);?}??
  22. ??
  23. ????@Override?public?String?getString()?{??
  24. ????????StringBuilder?sb?=?new?StringBuilder("\n【菜单】:"?+?name?+?"?信息:"?+?desc?+?"\n");??
  25. ????????for?(AbstractMenu?menu:?menus)?{?sb.append(menu.getString()).append("\n");?}??
  26. ????????return?sb.toString();??
  27. ????}??
  28. }??
  29. ??
  30. /*?叶子组件?*/??
  31. class?MilkTea?extends?AbstractMenu?{??
  32. ????private?String?name;??
  33. ????private?String?desc;??
  34. ????private?int?price;??
  35. ??
  36. ????MilkTea(String?name,?String?desc,?int?price)?{??
  37. ????????this.name?=?name;??
  38. ????????this.desc?=?desc;??
  39. ????????this.price?=?price;??
  40. ????}??
  41. ??
  42. ????@Override?public?void?add(AbstractMenu?menu)?{?/*未使用*/?}??
  43. ??
  44. ????@Override?public?AbstractMenu?get(int?index)?{?return?null;?}??
  45. ??
  46. ????@Override?public?String?getString()?{??
  47. ????????return?"?-?【奶茶】*?"?+?name?+?"?标注:"?+?desc?+?"?价格:"?+?price;??
  48. ????}??
  49. }??
  50. ??
  51. class?MilkTea?extends?AbstractMenu?{??
  52. ????//...??
  53. }??
  54. ??
  55. class?HandCake??extends?AbstractMenu?{??
  56. ????//...??
  57. }??
  58. ??
  59. class?FishBall??extends?AbstractMenu?{??
  60. ????//...??
  61. }??
  62. ??
  63. /*?客户端调用?*/??
  64. public?class?Store?{??
  65. ????public?static?void?main(String[]?args)?{??
  66. ????????AbstractMenu?mainMenu?=?new?Menu("大菜单",?"包含所有子菜单");??
  67. ????????AbstractMenu?drinkMenu?=?new?Menu("饮品菜单",?"都是喝的");??
  68. ????????AbstractMenu?eatMenu?=?new?Menu("小吃菜单",?"都是吃的");??
  69. ????????AbstractMenu?milkTea?=?new?MilkTea("珍珠奶茶",?"奶茶+珍珠",?5);??
  70. ????????AbstractMenu?juice?=?new?Juice("鲜榨猕猴桃枝",?"无添加即榨",?8);??
  71. ????????AbstractMenu?ball?=?new?FishBall("咖喱鱼蛋",?"微辣",?6);??
  72. ????????AbstractMenu?cake?=?new?HandCake("培根手抓饼",?"正宗台湾风味",?8);??
  73. ??
  74. ????????drinkMenu.add(milkTea);??
  75. ????????drinkMenu.add(juice);??
  76. ????????eatMenu.add(ball);??
  77. ????????eatMenu.add(cake);??
  78. ????????mainMenu.add(drinkMenu);??
  79. ????????mainMenu.add(eatMenu);??
  80. ??
  81. ????????System.out.println(mainMenu.getString());??
  82. ????}??
  83. }

输出结果


十.桥接模式(Bridge Pattern)

基于单一职责原则,如果系统中的类存在多个变化的维度,通过该模式可以将这几个维度分离出来, 然后进行独立扩展。这些分离开来的维度,通过在抽象层持有其他维度的引用来进行关联,就好像在两个维度间搭了桥一样,所以叫桥接模式。

代码示例(变化的三个维度:配餐,扒类)

Java代码
  1. /*?抽象部分?*/??
  2. abstract?class?Rations?{??
  3. ????abstract?String?rations();??
  4. }??
  5. ??
  6. /*?扩展抽象部分?*/??
  7. class?Rice?extends?Rations?{??
  8. ????@Override?public?String?rations()?{?return?"饭";?}??
  9. }??
  10. ??
  11. class?Spaghetti?extends?Rations?{??
  12. ????@Override?public?String?rations()?{?return?"意粉";?}??
  13. }??
  14. ??
  15. /*?实现部分?*/??
  16. abstract?class?Steak?{??
  17. ????Rations?rations;??
  18. ??
  19. ????Steak(Rations?rations)?{?this.rations?=?rations;?}??
  20. ??
  21. ????abstract?String?sale();??
  22. }??
  23. ??
  24. /*?具体实现部分?*/??
  25. class?BeefSteak?extends?Steak{??
  26. ????BeefSteak(Rations?rations)?{?super(rations);?}??
  27. ??
  28. ????@Override?public?String?sale()?{?return?"牛扒"+?(rations?==?null???""?:?rations.rations());?}??
  29. }??
  30. ??
  31. class?PorkSteak?extends?Steak?{??
  32. ????PorkSteak(Rations?rations)?{?super(rations);?}??
  33. ??
  34. ????@Override?public?String?sale()?{?return?"猪扒"+?(rations?==?null???""?:?rations.rations());?}??
  35. }??
  36. ??
  37. ??
  38. /*?客户端调用?*/??
  39. public?class?Restaurant?{??
  40. ????public?static?void?main(String[]?args)?{??
  41. ????????System.out.println("\n"?+?new?Date(System.currentTimeMillis()));??
  42. ????????System.out.println("==================");??
  43. ??
  44. ????????Steak?steak1?=?new?BeefSteak(new?Rice());??
  45. ????????System.out.println("卖出了一份:"?+?steak1.sale());??
  46. ??
  47. ????????Steak?steak2?=?new?PorkSteak(new?Spaghetti());??
  48. ????????System.out.println("卖出了一份:"?+?steak2.sale());??
  49. ??
  50. ????????Steak?steak3?=?new?PorkSteak(null);??
  51. ????????System.out.println("卖出了一份:"?+?steak3.sale());??
  52. ??
  53. ?????????System.out.println("==================");??
  54. }?

输出结果


十一.外观模式(Facade Pattern)

要求一个子系统的外部与内部的通信必须通过一个统一的对象进行,外观模式提供一个高层次的接口,使得子系统更易于使用。(其实就是封装,用于解决类与类间的依赖关系,比如本来是:玩家依赖于:Q,A,E,R等键位对象,现在变成只依赖与脚本对象从而降低了类间的耦合度。)

代码示例

Java代码
  1. /*?子系统?*/??
  2. class?A?{??
  3. ????String?a()?{?return?"A";?}??
  4. }??
  5. ??
  6. class?Q?{?/*?...?*/?}??
  7. ??
  8. class?Space?{?/*?...?*/?}??
  9. ??
  10. class?LeftClick?{?/*?...?*/?}??
  11. ??
  12. /*?外观类?*/??
  13. class?JiaoBen?{??
  14. ????A?a;??
  15. ????Q?q;??
  16. ????LeftClick?leftClick;??
  17. ????Space?space;??
  18. ??
  19. ????JiaoBen()?{??
  20. ????????a?=?new?A();??
  21. ????????leftClick?=?new?LeftClick();??
  22. ????????q?=?new?Q();??
  23. ????????space?=?new?Space();??
  24. ????}??
  25. ??
  26. ????String?锐雯()?{??
  27. ????????StringBuilder?sb?=?new?StringBuilder();??
  28. ????????sb.append(q.q()).append("?+?");??
  29. ????????sb.append(space.space()).append("?+?");??
  30. ????????sb.append(a.a()).append("?+?");??
  31. ????????sb.append(leftClick.leftClick()).append("?+?");??
  32. ????????sb.append(q.q()).append("?+?");??
  33. ????????sb.append(space.space()).append("?+?");??
  34. ????????sb.append(a.a()).append("?+?");??
  35. ????????sb.append(leftClick.leftClick()).append("?+?");??
  36. ????????sb.append(q.q()).append("?+?");??
  37. ????????sb.append(space.space()).append("?+?");??
  38. ????????sb.append(a.a()).append("?+?");??
  39. ????????sb.append(leftClick.leftClick()).append("\n");??
  40. ????????return?sb.toString();??
  41. ????}??
  42. }??
  43. ??
  44. /*?客户端调用?*/??
  45. public?class?XLoLer?{??
  46. ????public?static?void?main(String[]?args)?{??
  47. ????????JiaoBen?jiaoBen?=?new?JiaoBen();??
  48. ????????System.out.println("===?锐雯一键光速QA?===\n"?+?jiaoBen.锐雯());??
  49. ????}??
  50. }

输出结果


十二. 享元模式(Flyweight Pattern)

当存在多个相同对象时,可以使用享元模式减少相同对象创建引起的内存消耗,提高程序性能。说到共享,还分内部状态与外部状态

内部状态固定不变可共享的的部分,存储在享元对象内部,比如例子中的花色
外部状态可变不可共享的部分,一般由客户端传入享元对象内部,比如例子里的大小

示例代码

Java代码
  1. /*?抽象对象的父类?*/??
  2. abstract?class?Card?{??
  3. ????abstract?void?showCard(String?num);??//传入外部状态参数,大小??
  4. }??
  5. ??
  6. /*?具体享元对象?*/??
  7. public?class?SpadeCard?extends?Card{??
  8. ????public?SpadeCard()?{?super();?}??
  9. ??
  10. ????@Override?public?void?showCard(String?num)?{?System.out.println("黑桃:"?+?num);?}??
  11. }??
  12. ??
  13. public?class?HeartCard?extends?Card?{?/*?...?*/?}??
  14. ??
  15. public?class?ClubCard?extends?Card?{?/*?...?*/?}??
  16. ??
  17. public?class?DiamondCard?extends?Card?{?/*?...?*/?}??
  18. ??
  19. /*?享元工厂?*/??
  20. public?class?PokerFactory?{??
  21. ????static?final?int?Spade?=?0;??//黑桃??
  22. ????static?final?int?Heart??=?1;?//红桃??
  23. ????static?final?int?Club??=?2;?//梅花??
  24. ????static?final?int?Diamond??=?3;???//方块??
  25. ??
  26. ????public?static?Map?pokers?=?new?HashMap<>();??
  27. ??
  28. ????public?static?Card?getPoker(int?color)?{??
  29. ????????if?(pokers.containsKey(color))?{??
  30. ????????????System.out.print("对象已存在,对象复用...");??
  31. ????????????return?pokers.get(color);??
  32. ????????}?else?{??
  33. ????????????System.out.print("对象不存在,新建对象...");??
  34. ????????????Card?card;??
  35. ????????????switch?(color)?{??
  36. ????????????????case?Spade:?card?=?new?SpadeCard();?break;??
  37. ????????????????case?Heart:?card?=?new?HeartCard();?break;??
  38. ????????????????case?Club:?card?=?new?ClubCard();?break;??
  39. ????????????????case?Diamond:?card?=?new?DiamondCard();?break;??
  40. ????????????????default:?card?=?new?SpadeCard();?break;??
  41. ????????????}??
  42. ????????????pokers.put(color,card);??
  43. ????????????return?card;??
  44. ????????}??
  45. ????}??
  46. ??
  47. ??
  48. /*?客户端调用?*/??
  49. public?class?Player?{??
  50. ????public?static?void?main(String[]?args)?{??
  51. ????????for?(int?k?=?0;?k?10;?k?++){??
  52. ????????????Card?card?=?null;??
  53. ????????????//随机花色??
  54. ????????????switch?((int)(Math.random()*4))?{??
  55. ????????????????case?0:?card?=?PokerFactory.getPoker(PokerFactory.Spade);?break;??
  56. ????????????????case?1:?card?=?PokerFactory.getPoker(PokerFactory.Heart);?break;??
  57. ????????????????case?2:?card?=?PokerFactory.getPoker(PokerFactory.Club);?break;??
  58. ????????????????case?3:?card?=?PokerFactory.getPoker(PokerFactory.Diamond);?break;??
  59. ????????????}??
  60. ????????????if(card?!=?null)?{??
  61. ????????????????//随机大小??
  62. ????????????????int?num?=?(int)(Math.random()*13?+?1);??
  63. ????????????????switch?(num)?{??
  64. ????????????????????case?11:?card.showCard("J");?break;??
  65. ????????????????????case?12:?card.showCard("Q");?break;??
  66. ????????????????????case?13:?card.showCard("K");?break;??
  67. ????????????????????default:?card.showCard(num+"");?break;??
  68. ????????????????}??
  69. ????????????}??
  70. ????????}??
  71. ????}??
  72. }?

输出结果


十三.代理模式(Proxy Pattern)

引用代理对象的方式来访问目标对象,简单点说,就是在调用某个对象时加了一层,然后你可以在这一层做些手脚,比如权限控制,或者附加操作等。

代码示例

Java代码
  1. /*?抽象对象?*/??
  2. public?interface?FetchGoods?{??
  3. ????public?void?fetchShoes();??
  4. }??
  5. ??
  6. /*?真实对象?*/??
  7. public?class?Custom?implements?FetchGoods{??
  8. ????@Override?public?void?fetchShoes()?{?System.out.println("拿货");?}??
  9. }??
  10. ??
  11. /*?代理对象?*/??
  12. public?class?Agent?implements?FetchGoods{??
  13. ????@Override?public?void?fetchShoes()?{??
  14. ????????Custom?custom?=?new?Custom();??
  15. ????????custom.fetchShoes();??
  16. ????????this.callCustom();??
  17. ????}??
  18. ??
  19. ????public?void?callCustom()?{?System.out.println("通知顾客过来取件!");?}??
  20. }??
  21. ??
  22. /*?客户端调用?*/??
  23. public?class?Client?{??
  24. ????public?static?void?main(String[]?args)?{??
  25. ????????Agent?agent?=?new?Agent();??
  26. ????????agent.fetchShoes();??
  27. ????}??
  28. }?

输出结果


十四.策略模式(Strategy Pattern)

定义一系列的算法,把每个算法封装起来,并使得他们可以相互替换让算法独立于使用它的客户而变化。 一般用来替换if-else,个人感觉是面向过程与面向对象思想的过渡。

代码示例:(面向过程与面向对象的简易计算器)

面向过程简易计算器

Java代码
  1. public?class?Calculator?{??
  2. ????public?static?void?main(String[]?args)?{??
  3. ????????System.out.println("计算:1?+?1?=?"?+?compute("+",?1,?1));??
  4. ????????System.out.println("计算:1?-?1?=?"?+?compute("-",?1,?1));??
  5. ????????System.out.println("计算:1?*?1?=?"?+?compute("*",?1,?1));??
  6. ????????System.out.println("计算:1???1?=?"?+?compute("/",?1,?1));??
  7. ????}??
  8. ??
  9. ????public?static?float?compute(String?operator,?int?first,?int?second)?{??
  10. ????????switch?(operator)?{??
  11. ????????????case?"+":?return?first?+?second;??
  12. ????????????case?"-":?return?first?-?second;??
  13. ????????????case?"*":?return?first?*?second;??
  14. ????????????case?"/":?return?first?/?second;??
  15. ????????????default:?return?0.0f;??
  16. ????????}??
  17. ????}??
  18. }

面向对象(策略模式)简易计算器

Java代码
  1. /*?抽象策略类?*/??
  2. public?interface?Compute?{??
  3. ????String?compute(int?first,?int?second);??
  4. }??
  5. ??
  6. /*?具体策略类?*/??
  7. public?class?Add?implements?Compute{??
  8. ????@Override?public?String?compute(int?first,?int?second)?{??
  9. ????????return?"输出结果:"?+?first?+?"?+?"?+?second?+?"?=?"?+?(first?+?second);??
  10. ????}??
  11. }??
  12. ??
  13. public?class?Sub?implements?Compute{?/*?...?*/?}??
  14. ??
  15. public?class?Mul?implements?Compute{?/*?...?*/?}??
  16. ??
  17. public?class?Div?implements?Compute{?/*?...?*/?}??
  18. ??
  19. /*?上下文环境类?*/??
  20. public?class?Context?{??
  21. ????private?Compute?compute;??
  22. ??
  23. ????public?Context()?{?compute?=?new?Add();?}??
  24. ??
  25. ????public?void?setCompute(Compute?compute)?{?this.compute?=?compute;?}??
  26. ??
  27. ????public?void?calc(int?first,?int?second)?{???
  28. ????????System.out.println(compute.compute(first,?second));???
  29. ????}??
  30. }??
  31. ??
  32. /*?客户端调用?*/??
  33. public?class?Client?{??
  34. ????public?static?void?main(String[]?args)?{??
  35. ????????Context?context?=?new?Context();??
  36. ??
  37. ????????context.setCompute(new?Add());??
  38. ????????context.calc(1,2);??
  39. ??
  40. ????????context.setCompute(new?Sub());??
  41. ????????context.calc(3,4);??
  42. ??
  43. ????????context.setCompute(new?Mul());??
  44. ????????context.calc(5,6);??
  45. ??
  46. ????????context.setCompute(new?Div());??
  47. ????????context.calc(7,8);??
  48. ????}??
  49. }??

输出结果

??????


十五.观察者模式(Observer Pattern)

定义对象见的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并且自动更新

当对象间存在一对多关系的时候,使用观察者模式,当一个对象(被观察者)被修改时,会自动通知它的依赖对象们(观察者)。

这个模式基本都应该用过和听说过,关于概念就不多解释了,有兴趣看原文去~

代码示例

Java代码
  1. /*?抽象观察者?——?昆虫类?*/??
  2. public?interface?Insect?{??
  3. ????void?work();??
  4. ????void?unWork();??
  5. }??
  6. ??
  7. /*?具体观察者?——?蜜蜂类?*/??
  8. public?class?Bee?implements?Insect{??
  9. ????private?int?bId;????//蜜蜂编号??
  10. ????public?Bee(int?bId)?{?this.bId?=?bId;?}??
  11. ????@Override?public?void?work()?{?System.out.println("蜜蜂"+?bId?+?"采蜜");?}??
  12. ????@Override?public?void?unWork()?{?System.out.println("蜜蜂"+?bId?+?"回巢");?}??
  13. }??
  14. ??
  15. /*?抽象被观察者(注册,移除,通知观察者)?——?植物类?*/??
  16. public?interface?Plant?{??
  17. ????public?void?registerInsect(Insect?insect);??
  18. ????public?void?unregisterInsect(Insect?insect);??
  19. ????public?void?notifyInsect(boolean?isOpen);??
  20. }??
  21. ??
  22. /*?具体被观察者(定义一个集合存储观察者,实现相关方法)?——?花朵类?*/??
  23. public?class?Flower?implements?Plant?{??
  24. ????private?boolean?state;??
  25. ????private?List?insects?=?new?ArrayList<>();??
  26. ????public?boolean?isState()?{?return?state;?}??
  27. ??
  28. ????@Override?public?void?registerInsect(Insect?insect)?{?insects.add(insect);?}??
  29. ????@Override?public?void?unregisterInsect(Insect?insect)?{?insects.remove(insect);?}??
  30. ????@Override?public?void?notifyInsect(boolean?isOpen)?{??
  31. ????????state?=?isOpen;??
  32. ????????if?(state)?{??
  33. ????????????System.out.println("花开");??
  34. ????????????for?(Insect?insect?:?insects)?{?insect.work();?}??
  35. ????????}?else?{??
  36. ????????????System.out.println("花闭");??
  37. ????????????for?(Insect?insect?:?insects)?{?insect.unWork();?}??
  38. ????????}??
  39. ????}??
  40. }??
  41. ??
  42. /*?客户端调用?*/??
  43. public?class?Client?{??
  44. ????public?static?void?main(String[]?args)?{??
  45. ????????//创建被观察者??
  46. ????????Plant?flower?=?new?Flower();??
  47. ????????//创建三个观察者??
  48. ????????Insect?bee1?=?new?Bee(1);??
  49. ????????Insect?bee2?=?new?Bee(2);??
  50. ????????Insect?bee3?=?new?Bee(3);??
  51. ????????//注册观察者??
  52. ????????flower.registerInsect(bee1);??
  53. ????????flower.registerInsect(bee2);??
  54. ????????flower.registerInsect(bee3);??
  55. ????????//改变被观察者状态,先开后合??
  56. ????????flower.notifyInsect(true);??
  57. ????????System.out.println("===?太阳从东边到西边...?===");??
  58. ????????flower.notifyInsect(false);??
  59. ????????//最后解除注册??
  60. ????????flower.unregisterInsect(bee1);??
  61. ????????flower.unregisterInsect(bee2);??
  62. ????????flower.unregisterInsect(bee3);??
  63. ????}??
  64. }

输出结果


观察者模式的推与拉

推方式

被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是被观察者对象的全部或部分数据。(上面的例子就是推方式)

拉方式

被观察者对象再通知观察者时,只传递少量信息。如果观察者需要更详细的信息,可以主动到被观察者中获取,相当于观察者从被观察者中拉取数据。一般的套路是:**把主题对象自身通过update()方法传递给观察者,然后观察者在需要获取的时候,通过这个引用来获取**。

代码示例

微信订阅了某个公众号,当有更新的时候会推送提醒,收到提醒后,我们需要进入公众号然后点击对应信息查看详细内容。

Java代码
  1. /*?抽象观察者?——?用户?*/??
  2. public?interface?User?{??
  3. ????public?void?update(OfficialAccount?account);??
  4. }??
  5. ??
  6. /*?具体观察者?——?Android读者?*/??
  7. public?class?AndroidDev?implements?User?{??
  8. ????@Override?public?void?update(OfficialAccount?account)?{??
  9. ????????System.out.println("读者查看公众号更新信息:"?+??((CoderPig)account).getMsg());??
  10. ????}??
  11. }??
  12. ??
  13. /*?抽象被观察者?——?公众号?*/??
  14. public?abstract?class?OfficialAccount?{??
  15. ????private?List?userList?=?new?ArrayList<>();??
  16. ????public?void?registerUser(User?user)?{?userList.add(user);?}??
  17. ????public?void?unregisterUser(User?user)?{?userList.remove(user);?}??
  18. ????public?void?notifyUse()?{??
  19. ????????for?(User?user:?userList)?{??
  20. ????????????user.update(this);??
  21. ????????}??
  22. ????}??
  23. }??
  24. ??
  25. /*?具体被观察者?——?CoderPig公众号?*/??
  26. public?class?CoderPig?extends?OfficialAccount?{??
  27. ????private?String?msg;?//更新的文章??
  28. ????public?String?getMsg()?{?return?msg;?}??
  29. ????public?void?update(String?msg)?{??
  30. ????????this.msg?=?msg;??
  31. ????????System.out.println("公众号更新了文章:"?+?msg);??
  32. ????????this.notifyUse();???//通知用户有更新??
  33. ????}??
  34. }??
  35. ??
  36. /*?客户端调用?*/??
  37. public?class?Client?{??
  38. ????public?static?void?main(String[]?args)?{??
  39. ????????OfficialAccount?account?=?new?CoderPig();??
  40. ????????User?user?=?new?AndroidDev();??
  41. ????????account.registerUser(user);??
  42. ????????((CoderPig)account).update("《观察者模式》");??
  43. ????????account.unregisterUser(user);??
  44. ????}??
  45. }?

输出结果


Java中对观察者模式的支持(在Java.util中)

口诀被观察者实现继承Observable观察者实现Observer接口,然后有个很关键的地方:当通知变化的时候,需要调用setChange()方法!!!! 不用自己另外去写抽象观察者或抽象被观察者类,直接继承就能玩了,另外有一点要注意的是:Java内置的观察者模式通知多个观察者的顺序不是固定的,如果对通知顺序有所依赖的话,还是得自己实现观察者模式!

代码示例

Java代码
  1. /*?具体观察者?*/??
  2. public?class?AndroidDev?implements?Observer{??
  3. ????@Override?public?void?update(Observable?o,?Object?object)?{??
  4. ????????System.out.println("收到公众号更新信息:"?+?object);??
  5. ????}??
  6. }??
  7. ??
  8. /*?具体被观察者?*/??
  9. public?class?CoderPig?extends?Observable?{??
  10. ????private?String?msg;??
  11. ????public?String?getMsg()?{?return?msg;?}??
  12. ??
  13. ????public?void?update(String?msg)?{??
  14. ????????this.msg?=?msg;??
  15. ????????System.out.println("公众号更新了文章:"?+?msg);??
  16. ????????this.setChanged();??//这句话必不可少,通知改变??
  17. ????????this.notifyObservers(this.msg);?//这里用推的方式??
  18. ????}??
  19. }??
  20. ??
  21. /*?客户端调用?*/??
  22. public?class?Client?{??
  23. ????public?static?void?main(String[]?args)?{??
  24. ????????CoderPig?coderPig?=?new?CoderPig();??
  25. ????????AndroidDev?dev?=?new?AndroidDev();??
  26. ????????coderPig.addObserver(dev);??
  27. ????????coderPig.update("Java中对观察者模式的支持~");??
  28. ????????coderPig.deleteObserver(dev);??
  29. ????}??
  30. }

输出结果


十六.迭代器模式(Iterator Pattern)

提供一种方法顺序访问一个容器(聚合)对象各个元素,而又不暴露该对象的内部表示

从上面的定义可以知道,这个模式的使用场景:容器对象中的元素迭代访问

四个角色

UML类图

代码示例

Java代码
  1. /*?集合中的元素?*/??
  2. public?class?Song?{??
  3. ????private?String?name;??
  4. ????private?String?singer;??
  5. ????public?Song(String?name,?String?singer)?{??
  6. ????????this.name?=?name;??
  7. ????????this.singer?=?singer;??
  8. ????}??
  9. ??
  10. ????/*?getter和setter方法?*/??
  11. ??
  12. ????@Override?public?String?toString()?{???
  13. ????????return?"【歌名】"?+?name?+?"?-?"?+?singer;???
  14. ????}??
  15. }??
  16. ??
  17. /*?迭代器角色,第一项,下一个,判断是否能下一个,获取当前项。?*/??
  18. public?interface?Iterator?{??
  19. ????Song?first();??
  20. ????Song?next();??
  21. ????boolean?hashNext();??
  22. ????Song?currentItem();??
  23. }??
  24. ??
  25. /*?抽象容器,定义一个生成迭代器的方法?*/??
  26. interface?SongList?{??
  27. ????Iterator?getIterator();??
  28. }??
  29. ??
  30. /*?具体容器,继承抽象容器,并定义一个具体迭代器内部类?*/??
  31. public?class?MyStoryList?implements?SongList{??
  32. ????private?List?list?=?new?ArrayList<>();??
  33. ??
  34. ????public?MyStoryList(List?list)?{??
  35. ????????this.list?=?list;??
  36. ????}??
  37. ??
  38. ????@Override?public?Iterator?getIterator()?{??
  39. ????????return?new?SongListIterator();??
  40. ????}??
  41. ??
  42. ????private?class?SongListIterator?implements?Iterator?{??
  43. ????????private?int?cursor;??
  44. ??
  45. ????????@Override?public?Song?first()?{??
  46. ????????????cursor?=?0;??
  47. ????????????return?list.get(cursor);??
  48. ????????}??
  49. ??
  50. ????????@Override?public?Song?next()?{??
  51. ????????????Song?song?=?null;??
  52. ????????????cursor++;??
  53. ????????????if(hashNext())?{??
  54. ????????????????song?=?list.get(cursor);??
  55. ????????????}??
  56. ????????????return?song;??
  57. ????????}??
  58. ??
  59. ????????@Override?public?boolean?hashNext()?{??
  60. ????????????return?!(cursor?==?list.size());??
  61. ????????}??
  62. ??
  63. ????????@Override?public?Song?currentItem()?{??
  64. ????????????return?list.get(cursor);??
  65. ????????}??
  66. ????}??
  67. }??
  68. ??
  69. /*?客户端调用?*/??
  70. public?class?Client?{??
  71. ????public?static?void?main(String[]?args)?{??
  72. ????????List?list?=?new?ArrayList<>();??
  73. ????????list.add(new?Song("空白格","杨宗纬"));??
  74. ????????list.add(new?Song("那时候的我","刘惜君"));??
  75. ????????list.add(new?Song("黑泽明","陈奕迅"));??
  76. ????????list.add(new?Song("今天只做一件事","陈奕迅"));??
  77. ????????list.add(new?Song("童话镇","陈一发儿"));??
  78. ??
  79. ????????MyStoryList?songList?=?new?MyStoryList(list);??
  80. ??
  81. ????????Iterator?iterator?=?songList.getIterator();??
  82. ??
  83. ????????while?(iterator.hashNext())?{??
  84. ????????????System.out.println(iterator.currentItem().toString());??
  85. ????????????iterator.next();??
  86. ????????}??
  87. ????}??
  88. }

输出结果

PS:由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的时候都给提供了迭代器,并且这些语言提供的容器和迭代器在绝大多数情况下就可以满足我们的需要,所以现在需要我们自己去实践迭代器模式的场景还是比较少见的,我们只需要使用语言中已有的容器和迭代器就可以了。


十七.命令模式(Command Pattern)

使用场景行为请求者行为实现者解耦

定义:将一个请求封装成一个对象,从而可用不同的请求对客户端参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

代码示例

Java代码
  1. /*?元素对象??*/??
  2. public?class?Story?{??
  3. ????private?String?sName;??
  4. ????private?String?sUrl;??
  5. ??
  6. ????public?Story(String?sName,?String?sUrl)?{??
  7. ????????this.sName?=?sName;??
  8. ????????this.sUrl?=?sUrl;??
  9. ????}??
  10. ??
  11. ????/*getter和setter方法*/??
  12. }??
  13. ??
  14. /*?命令执行者?*/??
  15. public?class?StoryPlayer?{??
  16. ????private?int?cursor?=?0;?//当前播放项??
  17. ????private?int?pauseCursor?=?-1;???//暂停播放项??
  18. ????private?List?playList?=?new?ArrayList<>();???//播放列表??
  19. ??
  20. ????public?void?setPlayList(List?list)?{??
  21. ????????this.playList?=?list;??
  22. ????????cursor?=?0;??
  23. ????????System.out.println("更新播放列表...");??
  24. ????}??
  25. ??
  26. ????public?void?play()?{?/*?播放?*/?}??
  27. ????public?void?play(int?cursor)?{?/*?根据游标播放?*/?}??
  28. ????public?void?next()?{?/*?下一首?*/?}??
  29. ????public?void?pre()?{?/*?上一首?*/?}??
  30. ????public?void?pause()?{?/*?暂停?*/?}??
  31. ??
  32. }??
  33. ??
  34. /*?抽象命令接口?*/??
  35. public?interface?Command?{?void?execute();?}??
  36. ??
  37. /*?具体命令类?*/??
  38. public?class?SetListCommand?implements?Command?{??
  39. ????private?StoryPlayer?mPlayer;??
  40. ????private?List?mList?=?new?ArrayList<>();??
  41. ??
  42. ????public?SetListCommand(StoryPlayer?mPlayer)?{?this.mPlayer?=?mPlayer;?}??
  43. ??
  44. ????@Override?public?void?execute()?{?mPlayer.setPlayList(mList);?}??
  45. ??
  46. ????public?void?setPlayList(List?list)?{?this.mList?=?list;?}??
  47. }??
  48. ??
  49. public?class?PlayCommand?implements?Command?{??
  50. ????private?StoryPlayer?mPlayer;??
  51. ??
  52. ????public?PlayCommand(StoryPlayer?mPlayer)?{?this.mPlayer?=?mPlayer;?}??
  53. ??
  54. ????@Override?public?void?execute()?{?mPlayer.play();?}??
  55. }??
  56. ??
  57. public?class?PlayCommand?implements?Command?{?/*?...?*/?}??
  58. ??
  59. public?class?PauseCommand?implements?Command?{?/*?...?*/?}??
  60. ??
  61. public?class?NextCommand?implements?Command?{?/*?...?*/?}??
  62. ??
  63. public?class?PreCommand?implements?Command?{?/*?...?*/?}??
  64. ??
  65. ??
  66. /*?请求者类,调用命令对象执行具体操作?*/??
  67. public?class?Invoker?{??
  68. ????private?SetListCommand?setListCommand;??
  69. ????private?PlayCommand?playCommand;??
  70. ????private?PauseCommand?pauseCommand;??
  71. ????private?NextCommand?nextCommand;??
  72. ????private?PreCommand?preCommand;??
  73. ??
  74. ????public?void?setSetListCommand(SetListCommand?setListCommand)?{??
  75. ????????this.setListCommand?=?setListCommand;??
  76. ????}??
  77. ??
  78. ????public?void?setPlayCommand(PlayCommand?playCommand)?{??
  79. ????????this.playCommand?=?playCommand;??
  80. ????}??
  81. ??
  82. ????public?void?setPauseCommand(PauseCommand?pauseCommand)?{??
  83. ????????this.pauseCommand?=?pauseCommand;??
  84. ????}??
  85. ??
  86. ????public?void?setNextCommand(NextCommand?nextCommand)?{??
  87. ????????this.nextCommand?=?nextCommand;??
  88. ????}??
  89. ??
  90. ????public?void?setPreCommand(PreCommand?preCommand)?{??
  91. ????????this.preCommand?=?preCommand;??
  92. ????}??
  93. ??
  94. ????/*?设置播放列表?*/??
  95. ????public?void?setPlayList(List?list)?{???
  96. ????????setListCommand.setPlayList(list);??
  97. ????????setListCommand.execute();??
  98. ????}??
  99. ????public?void?play()?{?playCommand.execute();?}?/*?播放?*/??
  100. ????public?void?pause()?{?pauseCommand.execute();?}?/*?暂停?*/??
  101. ????public?void?next()?{?nextCommand.execute();?}???/*?下一首?*/??
  102. ????public?void?pre()?{?preCommand.execute();?}????/*?上一首?*/??
  103. }??
  104. ??
  105. /*?客户端调用?*/??
  106. public?class?Client?{??
  107. ????public?static?void?main(String[]?args)?{??
  108. ????????//实例化播放列表??
  109. ????????List?mList?=?new?ArrayList<>();??
  110. ????????mList.add(new?Story("白雪公主",""));??
  111. ????????mList.add(new?Story("青蛙的愿望",""));??
  112. ????????mList.add(new?Story("驴和妈",""));??
  113. ????????mList.add(new?Story("小青蛙的烦恼",""));??
  114. ????????mList.add(new?Story("三字经",""));??
  115. ??
  116. ????????//实例化接收者??
  117. ????????StoryPlayer?mPlayer?=?new?StoryPlayer();??
  118. ??
  119. ????????//实例化命令对象??
  120. ????????Command?setListCommand?=?new?SetListCommand(mPlayer);??
  121. ????????Command?playCommand?=?new?PlayCommand(mPlayer);??
  122. ????????Command?pauseCommand?=?new?PauseCommand(mPlayer);??
  123. ????????Command?nextCommand?=?new?NextCommand(mPlayer);??
  124. ????????Command?preCommand?=?new?PreCommand(mPlayer);??
  125. ??
  126. ????????//实例化请求者??
  127. ????????Invoker?invoker?=?new?Invoker();??
  128. ????????invoker.setSetListCommand((SetListCommand)?setListCommand);??
  129. ????????invoker.setPlayList(mList);??
  130. ????????invoker.setPlayCommand((PlayCommand)?playCommand);??
  131. ????????invoker.setPauseCommand((PauseCommand)?pauseCommand);??
  132. ????????invoker.setNextCommand((NextCommand)?nextCommand);??
  133. ????????invoker.setPreCommand((PreCommand)?preCommand);??
  134. ??
  135. ????????//测试调用??
  136. ????????invoker.play();??
  137. ????????invoker.next();??
  138. ????????invoker.next();??
  139. ????????invoker.next();??
  140. ????????invoker.next();??
  141. ????????invoker.next();??
  142. ????????invoker.pause();??
  143. ????????invoker.play();??
  144. ????}??
  145. }

输出结果


十八.备忘录模式(Memento Pattern)

简单点说,就是存档保存一个对象在某个时刻的状态或部分状态在未来某个时段需要时将其还原到原来记录状态的模式

代码示例

Java代码
  1. /*?备忘录角色?——?存档类*/??
  2. public?class?Memento?{??
  3. ????private?int?hp;??
  4. ????private?int?mp;??
  5. ????private?int?money;??
  6. ??
  7. ????public?Memento(int?hp,?int?mp,?int?money)?{??
  8. ????????this.hp?=?hp;??
  9. ????????this.mp?=?mp;??
  10. ????????this.money?=?money;??
  11. ????}??
  12. ??
  13. ????/*getter和setter方法*/??
  14. }??
  15. ??
  16. /*?发起人角色?——?角色类,属性定义,定义保存与恢复自身状态的方法?*/??
  17. public?class?Character?{??
  18. ????private?int?hp;??
  19. ????private?int?mp;??
  20. ????private?int?money;??
  21. ??
  22. ????public?Character(int?hp,?int?mp,?int?money)?{??
  23. ????????this.hp?=?hp;??
  24. ????????this.mp?=?mp;??
  25. ????????this.money?=?money;??
  26. ????}??
  27. ??
  28. ????/*getter和setter方法*/??
  29. ??
  30. ????public?void?showMsg()?{??
  31. ????????System.out.println("当前状态:|?HP:"?+?hp?+?"?|?MP:"?+?mp?+?"?|?金钱:"?+?money?+?"\n");??
  32. ????}??
  33. ??
  34. ????//创建一个备忘录,保存当前自身状态??
  35. ????public?Memento?save()?{?return?new?Memento(hp,?mp,?money);?}??
  36. ??
  37. ????//传入一个备忘录对象,恢复内部状态??
  38. ????public?void?restore(Memento?memento)?{??
  39. ????????this.hp?=?memento.getHp();??
  40. ????????this.mp?=?memento.getMp();??
  41. ????????this.money?=?memento.getMoney();??
  42. ????}??
  43. }??
  44. ??
  45. /*?备忘录管理者角色?——?只负责备忘录对象的传递!?多个存档的话可用集合存,根据索引取*/??
  46. public?class?Caretaker?{??
  47. ????private?Memento?memento;??
  48. ??
  49. ????public?Memento?getMemento()?{?return?memento;?}??
  50. ??
  51. ????public?void?setMemento(Memento?memento)?{?this.memento?=?memento;?}??
  52. }??
  53. ??
  54. /*?客户端调用?*/??
  55. public?class?Client?{??
  56. ????public?static?void?main(String[]?args)?{??
  57. ????????Caretaker?caretaker=?new?Caretaker();??
  58. ????????Character?character?=?new?Character(2000,1000,500);??
  59. ????????//存档??
  60. ????????System.out.println("===?存档中...?===");??
  61. ????????character.showMsg();??
  62. ????????caretaker.setMemento(character.save());??
  63. ??
  64. ????????System.out.println("===?单挑Boss,不敌,金钱扣除一半...?===");??
  65. ????????character.setHp(0);??
  66. ????????character.setHp(0);??
  67. ????????character.setHp(250);??
  68. ????????character.showMsg();??
  69. ??
  70. ????????//读档??
  71. ????????System.out.println("===?读取存档中...?===");??
  72. ????????character.restore(caretaker.getMemento());??
  73. ????????character.showMsg();??
  74. ????}??
  75. }

十九.中介者模式(Mediator Pattern)

用一个中介对象来封装一系列的对象交互,使得各对象不需要显式的相互引用, 从而使其耦合松散,而且可以独立的改变他们之间的交互。

中介者持有所有同事引用,然后在里面做一些逻辑操作,然后每个同事类持有中介者引用,依次完成交互。

这里的话需要与前面的外观模式,代理模式进行区分!

外观模式结构型,对子系统提供统一的接口,单向,所有请求都委托子系统完成,树型
代理模式结构型引用代理对象的方式来访问目标对象单向
中介者模式行为型,用一个中介对象封装一系列同事对象的交互行为双向一对多星型

UML类图

代码示例

Java代码
  1. /*?抽象中介类,有连接同事进行交互的方法*/??
  2. public?abstract?class?Mediator?{??
  3. ????abstract?void?contact(People?people,?String?msg);??
  4. }??
  5. ??
  6. /*?抽象同事类,相关属性,还有一个中介类的引用,因为所有同事都知道中介*/??
  7. public?abstract?class?People?{??
  8. ????protected?String?name;??
  9. ????protected?Mediator?mediator;????//每个人都知道中介??
  10. ??
  11. ????public?People(String?name,?Mediator?mediator)?{??
  12. ????????this.name?=?name;??
  13. ????????this.mediator?=?mediator;??
  14. ????}??
  15. }??
  16. ??
  17. /*?具体同事类,这里是房东和房客*/??
  18. public?class?Landlord?extends?People?{??
  19. ????public?Landlord(String?name,?Mediator?mediator)?{?super(name,?mediator);?}??
  20. ??
  21. ????public?void?contact(String?msg)?{?mediator.contact(this,?msg);?}??
  22. ??
  23. ????public?void?getMessage(String?msg)?{?System.out.println("【房东】"?+?name?+?":"?+?msg);?}??
  24. }??
  25. ??
  26. public?class?Tenant?extends?People?{??
  27. ????public?Tenant(String?name,?Mediator?mediator)?{?super(name,?mediator);?}??
  28. ??
  29. ????public?void?contact(String?msg)?{?mediator.contact(this,?msg);?}??
  30. ??
  31. ????public?void?getMessage(String?msg)?{?System.out.println("【房客】"?+?name?+?":"?+?msg);?}??
  32. }??
  33. ??
  34. /*?具体中介类,中介者知道所有的同事,实现交互方法时对调用者进行判断?
  35. ?实现对应的逻辑,比如这里的信息显示*/??
  36. public?class?HouseMediator?extends?Mediator?{??
  37. ????//中介者知道所有同事??
  38. ????private?Landlord?landlord;??
  39. ????private?Tenant?tenant;??
  40. ??
  41. ????public?Landlord?getLandlord()?{?return?landlord;?}??
  42. ????public?void?setLandlord(Landlord?landlord)?{?this.landlord?=?landlord;?}??
  43. ????public?Tenant?getTenant()?{?return?tenant;?}??
  44. ????public?void?setTenant(Tenant?tenant)?{?this.tenant?=?tenant;?}??
  45. ??
  46. ????@Override?void?contact(People?people,?String?msg)?{??
  47. ????????if(people?==?tenant)?tenant.getMessage(msg);??
  48. ????????else?landlord.getMessage(msg);??
  49. ????}??
  50. }??
  51. ??
  52. /*?客户端调用?*/??
  53. public?class?Client?{??
  54. ????public?static?void?main(String[]?args)?{??
  55. ????????//实例化中介者??
  56. ????????HouseMediator?mediator?=?new?HouseMediator();??
  57. ????????//实例化同事对象,传入中介者实例??
  58. ????????Landlord?landlord?=?new?Landlord("包租婆",mediator);??
  59. ????????Tenant?tenant?=?new?Tenant("小猪",mediator);??
  60. ????????//为中介者传入同事实例??
  61. ????????mediator.setLandlord(landlord);??
  62. ????????mediator.setTenant(tenant);??
  63. ????????//调用??
  64. ????????landlord.contact("单间500一个月,有兴趣吗?");??
  65. ????????tenant.contact("热水器,空调,网线有吗?");??
  66. ????????landlord.contact("都有。");??
  67. ????????tenant.contact("好吧,我租了。");??
  68. ????}??
  69. }

输出结果


二十.解释器模式(Interpreter Pattern)

用得比较少的一种模式,定义也比较枯涩难懂,实在不理解可以先看代码:

给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器,客户端可以使用这个解释器来解释这个语言中的句子。

个人理解

定义了一套简单语法,每个终结符有一个对应的值存起来了,然后当你输了一串终结符,最后解释能得出一个正确结果

代码示例能够解释加减法的解释器

Java代码
  1. /*?抽象表达式?*/??
  2. public?abstract?class?Expression?{??
  3. ????public?abstract?int?interpret(Context?context);??
  4. ????@Override?public?abstract?String?toString();??
  5. }??
  6. ??
  7. /*?非终结符表达式?——?加法和减法?*/??
  8. public?class?PlusExpression?extends?Expression{??
  9. ????private?Expression?leftExpression;??
  10. ????private?Expression?rightExpression;??
  11. ??
  12. ????public?PlusExpression(Expression?leftExpression,?Expression?rightExpression)?{??
  13. ????????this.leftExpression?=?leftExpression;??
  14. ????????this.rightExpression?=?rightExpression;??
  15. ????}??
  16. ??
  17. ????@Override?public?int?interpret(Context?context)?{??
  18. ????????return?leftExpression.interpret(context)?+?rightExpression.interpret(context);??
  19. ????}??
  20. ??
  21. ????@Override?public?String?toString()?{??
  22. ????????return?leftExpression.toString()?+?"?+?"?+?rightExpression.toString();??
  23. ????}??
  24. }??
  25. ??
  26. public?class?MinusExpression?extends?Expression{?/*?和减法类似?*/?}??
  27. ??
  28. /*?终结符表达式?——?常量与变量*/??
  29. public?class?ConstantExpression?extends?Expression?{??
  30. ????private?int?value;??
  31. ??
  32. ????public?ConstantExpression(int?value)?{?this.value?=?value;?}??
  33. ??
  34. ????@Override?public?int?interpret(Context?context)?{?return?value;?}??
  35. ??
  36. ????@Override?public?String?toString()?{?return?Integer.toString(value);?}??
  37. }??
  38. ??
  39. public?class?VariableExpression?extends?Expression?{??
  40. ????private?String?name;??
  41. ??
  42. ????public?VariableExpression(String?name)?{?this.name?=?name;?}??
  43. ??
  44. ????@Override?public?int?interpret(Context?context)?{?return?context.lookup(this);?}??
  45. ??
  46. ????@Override?public?String?toString()?{?return?name;?}??
  47. }??
  48. ??
  49. /*?上下文环境?——?用Map存放各个终结符对应的具体值*/??
  50. public?class?Context?{??
  51. ????private?Map?map?=?new?HashMap<>();??
  52. ??
  53. ????public?void?addExpression(Expression?expression,?int?value)?{?map.put(expression,?value);?}??
  54. ??
  55. ????public?int?lookup(Expression?expression)?{?return?map.get(expression);?}??
  56. }??
  57. ??
  58. /*?客户端调用?*/??
  59. public?class?Client?{??
  60. ????public?static?void?main(String[]?args)?{??
  61. ????????Context?context?=?new?Context();??
  62. ??
  63. ????????VariableExpression?a?=?new?VariableExpression("a");??
  64. ????????VariableExpression?b?=?new?VariableExpression("b");??
  65. ????????ConstantExpression?c?=?new?ConstantExpression(6);??
  66. ??
  67. ????????context.addExpression(a,?2);??
  68. ????????context.addExpression(b,?3);??
  69. ??
  70. ????????Expression?expression?=?new?PlusExpression(new?PlusExpression(a,b),new?MinusExpression(a,c));??
  71. ????????System.out.println(expression.toString()?+?"?=?"?+?expression.interpret(context));??
  72. ????}??
  73. }

输出结果


二十一.访问者模式(Visitor Pattern)

核心数据结构不变操作可变,结构与操作解耦的一种模式。
定义:封装一些作用域某种数据结构中的个元素的操作,在不改变这个
数据结构的前提下,定义作用于这些元素的新的操作

代码示例

Java代码
  1. /*?元素角色?——?游戏机接口,有一个传入访问者实例的方法?*/??
  2. public?interface?Machine?{??
  3. ????public?void?accept(Player?player);??
  4. }??
  5. ??
  6. /*?具体元素?——?投篮机,跳舞机和开车?*/??
  7. public?class?Shooting?implements?Machine?{??
  8. ????@Override?public?void?accept(Player?player)?{?player.visit(this);?}??
  9. ????public?String?feature()?{?return?"投篮机";?}??
  10. }??
  11. ??
  12. public?class?Dancing?implements?Machine?{?/*...*/?}??
  13. public?class?Driving?implements?Machine?{?/*...*/?}??
  14. ??
  15. /*?抽象访问者?——?定义元素对应的访问方法,传入相应实例*/??
  16. public?interface?Player?{??
  17. ????public?void?visit(Shooting?machine);??
  18. ????public?void?visit(Dancing?machine);??
  19. ????public?void?visit(Driving?machine);??
  20. }??
  21. ??
  22. /*?具体访问者?——?男女性玩家?*/??
  23. public?class?MalePlayer?implements?Player{??
  24. ????@Override?public?void?visit(Shooting?machine)?{???
  25. ????????System.out.println("男性玩家玩:"?+?machine.feature());??
  26. ????}??
  27. ??
  28. ????@Override?public?void?visit(Dancing?machine)?{??
  29. ????????System.out.println("男性玩家玩:"?+?machine.feature());??
  30. ????}??
  31. ??
  32. ????@Override?public?void?visit(Driving?machine)?{??
  33. ????????System.out.println("男性玩家玩:"?+?machine.feature());??
  34. ????}??
  35. }??
  36. ??
  37. public?class?FemalePlayer?implements?Player{?/*...*/?}??
  38. ??
  39. /*?对象结构?——?管理元素集合,并且可迭代访问者访问?*/??
  40. public?class?GameRoom??{??
  41. ????private?List?machines?=?new?ArrayList<>();??
  42. ????public?void?add(Machine?machine)?{?machines.add(machine);?}??
  43. ????public?void?action(Player?player)?{??
  44. ????????for?(Machine?machine:?machines)?{?machine.accept(player);?}??
  45. ????}??
  46. }??
  47. ??
  48. /*?客户端调用?*/??
  49. public?class?Client?{??
  50. ????public?static?void?main(String[]?args)?{??
  51. ????????GameRoom?room?=?new?GameRoom();??
  52. ????????room.add(new?Shooting());??
  53. ????????room.add(new?Dancing());??
  54. ????????room.add(new?Driving());??
  55. ??
  56. ????????Player?player1?=?new?MalePlayer();??
  57. ????????Player?player2?=?new?FemalePlayer();??
  58. ??
  59. ????????room.action(player1);??
  60. ????????room.action(player2);??
  61. ????}??
  62. }

输出结果


二十二.责任链模式(Chain of Responsibility Pattern)

使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。(典型代表:Android里的事件传递机制)

代码示例

Java代码
  1. /*?抽象处理者?*/??
  2. public?abstract?class?Handler?{??
  3. ????private?Handler?nextHandler;?/*?下家处理者?*/??
  4. ??
  5. ????public?Handler?getNextHandler()?{?return??nextHandler;?}??
  6. ??
  7. ????public?void?setNextHandler(Handler?nextHandler)?{?this.nextHandler?=?nextHandler;?}??
  8. ??
  9. ????public?abstract?void?handlerRequest(String?str,?int?money);???/*?请求?*/??
  10. }??
  11. ??
  12. /*?具体处理者?——?哥哥,爸爸,妈妈,依次传递*/??
  13. public?class?Brother?extends?Handler?{??
  14. ????@Override?public?void?handlerRequest(String?str,?int?money)?{??
  15. ????????if(money?<=?100)?{??
  16. ????????????System.out.println("哥哥:100块,哥哥还是有的,给你~");??
  17. ????????}?else?{??
  18. ????????????if(getNextHandler()?!=?null)?{??
  19. ????????????????System.out.println("哥哥:大于100块,哥哥木有那么多钱,找粑粑去~");??
  20. ????????????????getNextHandler().handlerRequest(str,?money);??
  21. ????????????}?else?{??
  22. ????????????????System.out.println("哥哥:大于100块,哥哥木有那么多钱,粑粑不在家~");??
  23. ????????????}??
  24. ????????}??
  25. ????}??
  26. }??
  27. ??
  28. public?class?Father?extends?Handler?{??
  29. ????@Override?public?void?handlerRequest(String?str,?int?money)?{??
  30. ????????if(money?<=?500)?{??
  31. ????????????System.out.println("粑粑:500块,粑粑还是有的,给你~");??
  32. ????????}?else?{??
  33. ????????????if(getNextHandler()?!=?null)?{??
  34. ????????????????System.out.println("粑粑:大于500块,粑粑木有那么多钱,找麻麻去~");??
  35. ????????????????getNextHandler().handlerRequest(str,?money);??
  36. ????????????}?else?{??
  37. ????????????????System.out.println("粑粑:大于500块,粑粑木有那么多钱,麻麻不在家~");??
  38. ????????????}??
  39. ????????}??
  40. ????}??
  41. }??
  42. ??
  43. public?class?Mother?extends?Handler?{??
  44. ????@Override?public?void?handlerRequest(String?str,?int?money)?{??
  45. ????????if(money?<=?1000)?{??
  46. ????????????System.out.println("麻麻:1000块,麻麻还是有的,给你~");??
  47. ????????}?else?{??
  48. ????????????System.out.println("麻麻:你拿那么多钱干嘛?");??
  49. ????????}??
  50. ????}??
  51. }??
  52. ??
  53. /*?客户端调用?*/??
  54. public?class?Client?{??
  55. ????public?static?void?main(String[]?args)?{??
  56. ????????Brother?brother?=?new?Brother();??
  57. ????????Father?father?=?new?Father();??
  58. ????????Mother?mother?=?new?Mother();??
  59. ??
  60. ????????//指定下家??
  61. ????????brother.setNextHandler(father);??
  62. ????????father.setNextHandler(mother);??
  63. ??
  64. ????????brother.handlerRequest("要钱",1200);??
  65. ????}??
  66. }

输出结果

另外责任链模式还分纯与不纯

  • 纯责任链,要么承担全部责任,要么责任推个下家,不允许在某处承担部分或者全部责任,然后又把责任推给下家

  • 不纯责任链,责任在某处部分或全部被处理后,还向下传递。


二十三.状态模式(State Pattern)

定义:当一个对象的内在状态发生改变时允许改变其行为,这个对象看起来像是改变了它的类。

套路

抽象出状态State,然后实现该接口,然后具体化不同状态,做不同的操作,然后写一个Context,里面存储一个State的实例,然后定义一个可以修改State实例的方法,并在里面去调用实例的行为方法。

示例代码

Java代码
  1. /*?抽象状态?*/??
  2. public?interface?State?{??
  3. ????public?void?doSomeThing();??
  4. }??
  5. ??
  6. /*?具体状态?*/??
  7. public?class?MorningState?implements?State?{??
  8. ????@Override?public?void?doSomeThing()?{?System.out.println("早上赖床!");?}??
  9. }??
  10. ??
  11. public?class?AfternoonState?implements?State?{??
  12. ????@Override?public?void?doSomeThing()?{?System.out.println("下午学习!");?}??
  13. }??
  14. ??
  15. public?class?EveningState?implements?State?{??
  16. ????@Override?public?void?doSomeThing()?{?System.out.println("晚上打球!");?}??
  17. }??
  18. ??
  19. /*?上下文环境?*/??
  20. public?class?Context?{??
  21. ????public?void?setState(State?state)?{??
  22. ????????System.out.println("状态改变");??
  23. ????????state.doSomeThing();??
  24. ????}??
  25. }??
  26. ??
  27. /*?客户端调用?*/??
  28. public?class?Client?{??
  29. ????public?static?void?main(String[]?args)?{??
  30. ????????MorningState?morningState?=?new?MorningState();??
  31. ????????AfternoonState?afternoonState?=?new?AfternoonState();??
  32. ????????EveningState?eveningState?=?new?EveningState();??
  33. ??
  34. ????????Context?context?=?new?Context();??
  35. ????????context.setState(morningState);??
  36. ????????context.setState(afternoonState);??
  37. ????????context.setState(eveningState);??
  38. ????}??
  39. }

输出结果


二十四.模板方法模式(Template Method Pattern)

定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可冲定义该算法的某些特定步骤。(定义比较抽象,举之前工厂模式做奶茶的例子帮助理解下)

奶茶的制作步骤:加奶,加茶,加料,打包

在这几个步骤中,加奶,加茶,加料这几步是固定,而打包的话则是不固定的,有些用户喜欢找个小桌子喝喝奶茶吹吹水,有些喜欢带回家,存在可变性。

对于这种可变的步骤,可以使用一个叫做钩子的东西,其实就是一种被声明在抽象类的方法,可以为空或者默认的实现。钩子的存在可以让子类有能力对算法的不同点进行挂钩,是否需要挂钩由子类决定。比如例子通过一个标记确定是否需要打包,子类中可以定义一个方法来调用这个方法。

代码示例

Java代码
  1. /*?抽象模板?*/??
  2. public?abstract?class?Tea?{??
  3. ????protected?void?加奶()?{?System.out.println("加入三花淡奶");?}??
  4. ????protected?abstract?void?加茶();??
  5. ????protected?abstract?void?加料();??
  6. ????protected??void?打包()?{?System.out.println("用打包机打包");?}??
  7. ??
  8. ????protected?boolean?是否打包()?{?return?true;?}?????//钩子方法??
  9. ??
  10. ????public?final?void?make()?{??
  11. ????????System.out.println("===?开始制作?===");??
  12. ????????加奶();??
  13. ????????加茶();??
  14. ????????加料();??
  15. ????????if(是否打包())?{?打包();?}??
  16. ????????System.out.println("===?制作完毕?===");??
  17. ????}??
  18. }??
  19. ??
  20. /*?具体模板?*/??
  21. public?class?RedTeaMilkTea?extends?Tea?{??
  22. ????@Override?protected?void?加茶()?{?System.out.println("加入红茶");?}??
  23. ????@Override?protected?void?加料()?{?System.out.println("加入珍珠");?}??
  24. }??
  25. ??
  26. public?class?GreenTeaMilkTea?extends?Tea?{??
  27. ????private?boolean?isPack?=?true;??
  28. ????public?GreenTeaMilkTea(boolean?isPack)?{?this.isPack?=?isPack;?}??
  29. ??
  30. ????@Override?protected?void?加茶()?{?System.out.println("加入绿茶");?}??
  31. ????@Override?protected?void?加料()?{?System.out.println("加入椰果");?}??
  32. ????@Override?protected?boolean?是否打包()?{?return?isPack;?}??
  33. }??
  34. ??
  35. /*?客户端调用?*/??
  36. public?class?Client?{??
  37. ????public?static?void?main(String[]?args)?{??
  38. ????????Tea?tea1?=?new?RedTeaMilkTea();??
  39. ????????Tea?tea2?=?new?GreenTeaMilkTea(false);??
  40. ??
  41. ????????tea1.make();??
  42. ????????System.out.println("");??
  43. ????????tea2.make();??
  44. ????}??
  45. }

输出结果


To be continue

本节各种设计模式示例代码下载:https://github.com/coder-pig/DesignPatternsExample

转自:简书

除非特别注明,鸡皇冠现金官网hg6388|首页文章均为原创
转载请标明本文地址:http://www.jizhuomi.com/software/757.html
2017年8月25日
作者:鸡皇冠现金官网hg6388|首页 分类:软件开发 浏览: 评论:0