[关闭]
@snail-lb 2017-02-28T15:23:20.000000Z 字数 39633 阅读 824

设计模式(视频总结)

java进阶


一、简单工厂模式(Simple Factory)

简单工厂模式:

简单工厂模式属于类的创建型模式,又叫静态工厂方法模式,通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

角色:

1.工厂角色
简单工厂的核心 ,它负责实现创建所有实例的内部逻辑,工厂类可以被外界直接调用创建所需产品对象。
2.抽象角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例的公共接口
3.具体产品角色
简单工厂所创建的具体实例对象。

  1. //工厂角色(版本一)
  2. public class FruitFactory {
  3. public static Fruit getApple(){
  4. return new Apple();
  5. }
  6. public static Fruit getBanana(){
  7. return new Banana();
  8. }
  9. }
  1. //抽象角色
  2. public interface Fruit {
  3. public void get();
  4. }
  1. //产品
  2. public class Apple implements Fruit{
  3. @Override
  4. public void get() {
  5. System.out.println("采集苹果");
  6. }
  7. }
  1. //产品
  2. public class Banana implements Fruit{
  3. @Override
  4. public void get() {
  5. System.out.println("采集香蕉");
  6. }
  7. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Fruit apple = FruitFactory.getApple();
  5. Fruit banana = FruitFactory.getBanana();
  6. apple.get();
  7. banana.get();
  8. }
  9. }

以上就是一个简单工厂模式
现对工厂角色进行改进:

  1. //版本二(常用)
  2. public static Fruit getFruti(String type) throws InstantiationException, IllegalAccessException{
  3. if(type.equalsIgnoreCase("apple")){
  4. return Apple.class.newInstance();
  5. }else if(type.equalsIgnoreCase("banana")){
  6. return Banana.class.newInstance();
  7. }else{
  8. System.out.println("找不到响应的类");
  9. return null;
  10. }
  11. }

再改进

  1. //版本三
  2. public static Fruit getFruit(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
  3. Class<?> fruit = Class.forName(type);//type必须是类的完全限定名
  4. return (Fruit) fruit.newInstance();
  5. }
  1. //版本三的测试程序
  2. Fruit apple = FruitFactory.getFruit("simpleFactory_4.Apple");
  3. Fruit banana = FruitFactory.getFruit("simpleFactory_4.Banana");
  4. apple.get();
  5. banana.get();

二、工厂方法模式(Factory Method)

意图:

定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法是一个类的实例化延迟到其子类。

适用性:

  1. 当一个类不知道它所必须创建的对象的类的时候。
  2. 当一个类希望由它的子类来制定它所创建的对象的时候。
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望哪一个帮助子类是代理这一信息局部化的时候。

角色:

  1. 抽象工厂角色
    工厂方法模式的核心,任何工厂类都必须实现这个借口。
  2. 具体工厂角色
    具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
  3. 抽象角色
    工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口
  4. 具体产品角色
    工厂方法模式所创建的具体的实例对象

代码:

  1. //抽象工厂角色
  2. public interface FruitFactory {
  3. public Fruit getFruit();
  4. }
  1. //具体工厂角色
  2. public class AppleFactory implements FruitFactory {
  3. @Override
  4. public Fruit getFruit() {
  5. return new Apple();
  6. }
  7. }
  1. //具体工厂角色
  2. public class BananaFactory implements FruitFactory {
  3. @Override
  4. public Fruit getFruit() {
  5. return new Banana();
  6. }
  7. }
  1. //抽象角色
  2. public interface Fruit {
  3. public void get();
  4. }
  1. //具体产品角色
  2. public class Apple implements Fruit{
  3. @Override
  4. public void get() {
  5. System.out.println("采集苹果");
  6. }
  7. }
  1. //具体产品角色
  2. public class Banana implements Fruit{
  3. @Override
  4. public void get() {
  5. System.out.println("采集香蕉");
  6. }
  7. }
  1. //测试方法
  2. public class Main {
  3. public static void main(String[] args) {
  4. Fruit apple = new AppleFactory().getFruit();
  5. apple.get();
  6. Fruit banana = new BananaFactory().getFruit();
  7. banana.get();
  8. }
  9. }

工厂方法模式和简单工厂模式的比较

  1. 工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象的工厂类,而简单工厂模式把核心放在一个具体的类上。
    1. 工厂方法模式之所以有一个别名叫多态工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
    2. 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的复合“开放-封闭”原则,而简单工厂模式再添加新产品对象后不得不修改工厂方法,扩展性不是很好。
    3. 工厂方法模式退化后可以演变成简单工厂模式。

三、 抽象工厂模式(Abstract Factory)

抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的,抽象工厂模式可以指定向客户端提供一个接口,使得客户端不必指定产品具体类型的情况下,能够创建产品族的产品对象。

意图:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

适用性:

  1. 一个系统要独立于它的产品的创建、组合和表示时。
  2. 一个系统要有多个产品系列中的一个来配置时。
  3. 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
  4. 当你提供一个产品库,而只想显示它们的接口而不是实现时。

角色:

  1. 抽象工厂角色
    抽象工厂模式的核心,包含对多个产品结构的申明,任何工厂类都必须实现这个接口。
  2. 具体工厂角色
    具体工厂角色类是抽象工厂的一个实现负责实例化某个产品族的产品对象。
  3. 抽象角色
    抽象模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口
  4. 具体产品角色
    抽象模式所创建的具体实例对象

抽象工厂方法对应产品结构,具体工厂对应产品族。

  1. //抽象工厂角色
  2. public interface FruitFactory {
  3. //实例化苹果
  4. public Fruit getApple();
  5. //实例化Banana
  6. public Fruit getBanana();
  7. }
  1. //具体工厂角色
  2. public class NorthFruitFactory implements FruitFactory {
  3. @Override
  4. public Fruit getApple() {
  5. return new NorthApple();
  6. }
  7. @Override
  8. public Fruit getBanana() {
  9. return new NorthBanana();
  10. }
  11. }
  1. //具体工厂角色
  2. public class SouthFruitFactory implements FruitFactory {
  3. @Override
  4. public Fruit getApple() {
  5. return new SouthApple();
  6. }
  7. @Override
  8. public Fruit getBanana() {
  9. return new SouthBanana();
  10. }
  11. }
  1. //抽象角色
  2. public interface Fruit {
  3. public void get();
  4. }
  1. //抽象角色
  2. public abstract class Apple implements Fruit{
  3. public abstract void get();
  4. }
  1. //抽象角色
  2. public abstract class Banana implements Fruit{
  3. public abstract void get();
  4. }
  1. //具体产品角色
  2. public class NorthApple extends Apple{
  3. @Override
  4. public void get() {
  5. System.out.println("采集北方苹果");
  6. }
  7. }
  1. //具体产品角色
  2. public class NorthBanana extends Banana{
  3. @Override
  4. public void get() {
  5. System.out.println("采集北方香蕉");
  6. }
  7. }
  1. //具体产品角色
  2. public class SouthApple extends Apple{
  3. @Override
  4. public void get() {
  5. System.out.println("采集南方苹果");
  6. }
  7. }
  1. //具体产品角色
  2. public class SouthBanana extends Banana{
  3. @Override
  4. public void get() {
  5. System.out.println("采集南方香蕉");
  6. }
  7. }
  1. //测试方法
  2. public class Main {
  3. public static void main(String[] args) {
  4. NorthFruitFactory northFruitFactory = new NorthFruitFactory();
  5. Fruit northApple = northFruitFactory.getApple();
  6. northApple.get();
  7. Fruit northBanana = northFruitFactory.getBanana();
  8. northBanana.get();
  9. System.out.println("**********");
  10. SouthFruitFactory southFruitFactory = new SouthFruitFactory();
  11. Fruit southApple = southFruitFactory.getApple();
  12. southApple.get();
  13. Fruit southBanana = southFruitFactory.getBanana();
  14. southBanana.get();
  15. }
  16. }

如果要新增的话,我们只需要添加一个产品链
比如我们如果还有一个温室苹果和温室香蕉的话,需要新增以下类:
GreenhouseApple.java
GreenhouseBanana.java
GreenhouseFruitFactory.java
这样既可新增一个产品链。
但是如果需要添加一个新的产品,那么我们必须修改所有的工厂方法,新增get方法。

四、 单例模式(Singleton)

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。

定义:

保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

适用性:

  1. 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
  2. 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能实现一个扩展的实例时。

1. 饿汉式

  1. public class Person {
  2. public static final Person person = new Person();
  3. private String name;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. //构造函数私有化
  11. private Person(){}
  12. //提供一个全局的静态方法
  13. public static Person getPerson(){
  14. return person;
  15. }
  16. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Person person_1 = Person.getPerson();
  5. System.out.println(person_1.hashCode());
  6. Person person_2 = Person.getPerson();
  7. System.out.println(person_2.hashCode());
  8. }
  9. }

2. 懒汉式(非线程安全)

  1. public class Person2 {
  2. private static Person2 person;
  3. private String name;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. //构造函数私有化
  11. private Person2(){}
  12. //提供一个全局的静态方法
  13. public static Person2 getPerson(){
  14. if(person == null){
  15. person = new Person2();
  16. }
  17. return person;
  18. }
  19. }
测试函数同上

3.双重检查(线程安全)

  1. public class Person3 {
  2. private static Person3 person;
  3. private String name;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. //构造函数私有化
  11. private Person3(){}
  12. //提供一个全局的静态方法
  13. public static Person3 getPerson(){
  14. if(person == null){
  15. synchronized (Person3.class){
  16. if(person == null){
  17. person = new Person3();
  18. }
  19. }
  20. }
  21. return person;
  22. }
  23. }
测试方法同上

五、 原型模式(Prototype)

原型模式是一种对象创建型模式,它采用复制原型对象的方法来创建对象的实例。使用原型模式创建的实例,具有与原型一样的数据。
1. 由原型对象自身创建目标对象,也就是说,对象创建这一动作发自原型对象本身。
2. 目标对象是原型对象的一个克隆。也就是说,通过原型对象模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。
3. 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

适用性:

当要实例化的类实在运行时刻指定时,例如通过动态装载;或者为了避免创建一个与产品类层次平行的工厂类层次是;或者当一个类的实例只能有几种不同状态中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

实现方法:

  1. 实现Cloneable接口
  2. 编写clone方法

代码演示:

  1. public class Person implements Cloneable{
  2. private String name;
  3. private int age;
  4. private String sex;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public int getAge() {
  12. return age;
  13. }
  14. public void setAge(int age) {
  15. this.age = age;
  16. }
  17. public String getSex() {
  18. return sex;
  19. }
  20. public void setSex(String sex) {
  21. this.sex = sex;
  22. }
  23. public Person clone() {
  24. try {
  25. return (Person) super.clone();
  26. } catch (CloneNotSupportedException e) {
  27. e.printStackTrace();
  28. return null;
  29. }
  30. }
  31. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Person person1 = new Person();
  5. person1.setName("王小二");
  6. person1.setAge(23);
  7. person1.setSex("男");
  8. Person person2 = person1;
  9. Person person3 = person1.clone();
  10. System.out.println("person1:" + person1.hashCode() + " " +
  11. person1.getName() + " " + person1.getAge() + " " + person1.getSex());
  12. System.out.println("person2:" + person2.hashCode() + " " +
  13. person2.getName() + " " + person2.getAge() + " " + person2.getSex());
  14. System.out.println("person3:" + person3.hashCode() + " " +
  15. person3.getName() + " " + person3.getAge() + " " + person3.getSex());
  16. }
  17. }

运行结果:

person1:705927765 王小二 23 男
person2:705927765 王小二 23 男
person3:366712642 王小二 23 男

浅度克隆:如果Person中的某个属性是一个引用值的话,浅度克隆不会克隆这个引用对象。
深度克隆:克隆Person中所有的对象。

以上是浅度克隆,如果要使用深度克隆,可以手动在clone中复制引用对象完成深度克隆。

六、 建造者模式(Builder)

建造者模式也称生成器模式,是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态的创建具有复合属性的对象。

意图:

将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。

适用性:

  1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  2. 当构造过程必须允许被构造的对象有不同的表示时。
    代码示例:
  1. //
  2. public class House {
  3. //底板
  4. private String floor;
  5. //墙
  6. private String wall;
  7. //屋顶
  8. private String housetop;
  9. //省略get、set方法
  10. }
  1. //施工队接口
  2. public interface HouseBuilder {
  3. //修地板
  4. public void makeFloor();
  5. //修墙
  6. public void makeWall();
  7. //修屋顶
  8. public void makeHousetop();;
  9. public House getHouse();
  10. }
  1. //具体施工队
  2. public class PingFangBuilder implements HouseBuilder {
  3. House house = new House();
  4. @Override
  5. public void makeFloor() {
  6. house.setFloor("平方--->地板");
  7. }
  8. @Override
  9. public void makeWall() {
  10. house.setWall("平方--->墙");
  11. }
  12. @Override
  13. public void makeHousetop() {
  14. house.setHousetop("平方--->房顶");
  15. }
  16. @Override
  17. public House getHouse() {
  18. return house;
  19. }
  20. }
  1. //设计者
  2. public class HouseDicretor {
  3. private HouseBuilder builder;
  4. public HouseDicretor(HouseBuilder builder) {
  5. this.builder = builder;
  6. }
  7. public void makeHouse(){
  8. builder.makeFloor();
  9. builder.makeWall();
  10. builder.makeHousetop();
  11. }
  12. }
  1. //测试方法
  2. public class Main {
  3. public static void main(String[] args) {
  4. //客户直接造房子
  5. House house = new House();
  6. house.setWall("墙");
  7. house.setFloor("底板");
  8. house.setHousetop("屋顶");
  9. //由工程队来修
  10. HouseBuilder builder = new PingFangBuilder();
  11. //设计者来做
  12. HouseDicretor dicretor = new HouseDicretor(builder);
  13. dicretor.makeHouse();
  14. House pingfangHouse = builder.getHouse();
  15. System.out.println(pingfangHouse.getFloor());
  16. System.out.println(pingfangHouse.getWall());
  17. System.out.println(pingfangHouse.getHousetop());
  18. }
  19. }

运行结果:

平方--->地板
平方--->墙
平方--->房顶

八、 装饰模式(Decorator)

装饰模式又叫包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。

角色:

  1. 抽象组件角色: 一个抽象接口,是被装饰类和装饰类的父接口。
  2. 具体组件角色:为抽象组件的实现类。
  3. 抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
  4. 具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。

意图:

动态的给一个对象添加一些额外的职责。

适用性:

  1. 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  2. 处理那些可以撤销的职责
  3. 当不能采用生成子类的方法进行扩充时,一种情况是可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况是可能是因为类定义被隐藏,或类定义不能用于生成子类。

代码演示:

  1. //抽象组件角色
  2. public interface Car {
  3. public void show();
  4. public void run();
  5. }
  1. //具体组件角色
  2. public class RunCar implements Car {
  3. @Override
  4. public void show() {
  5. this.run();
  6. }
  7. @Override
  8. public void run() {
  9. System.out.println("可以跑");
  10. }
  11. }
  1. //抽象装饰角色
  2. public abstract class CarDecorator implements Car{
  3. private Car car;
  4. public Car getCar() {
  5. return car;
  6. }
  7. public void setCar(Car car) {
  8. this.car = car;
  9. }
  10. public CarDecorator(Car car) {
  11. this.car = car;
  12. }
  13. public abstract void show();
  14. }
  1. //具体装饰角色
  2. public class FlyCarDecorator extends CarDecorator {
  3. public FlyCarDecorator(Car car) {
  4. super(car);
  5. }
  6. @Override
  7. public void run() {
  8. }
  9. @Override
  10. public void show() {
  11. this.getCar().show();
  12. this.fly();
  13. }
  14. public void fly(){
  15. System.out.println("可以飞");
  16. }
  17. }
  1. //具体装饰角色
  2. public class SwimCarDecorator extends CarDecorator {
  3. public SwimCarDecorator(Car car) {
  4. super(car);
  5. }
  6. @Override
  7. public void run() {
  8. }
  9. @Override
  10. public void show() {
  11. this.getCar().show();
  12. this.swim();
  13. }
  14. public void swim() {
  15. System.out.println("可以游");
  16. }
  17. }
  1. //测试类
  2. public class Main {
  3. public static void main(String[] args) {
  4. Car runCar = new RunCar();
  5. CarDecorator flyCar = new FlyCarDecorator(runCar);
  6. CarDecorator swimCar = new SwimCarDecorator(flyCar);
  7. swimCar.show();
  8. }
  9. }

运行结果:

可以跑
可以飞
可以游

九、 策略模式(Strategy)

策略模式也是行为模式的一种,它对一系列算法加以封装,为所有算法定义一个抽象的接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定。

角色:

  1. Strategy:策略(算法)抽象。
  2. ConcreteStrategy:各种策略(算法)的具体实现。
  3. Context:策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环境决定。

适用性:

  1. 许多相关类仅仅是行为有异。“策略”提供一种用多个行为中的一个行为来配置一个类的方法。
  2. 需要使用一个算法的不同变体。例如,你可能会定义一些反应不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次是,可以使用策略模式。
  3. 算法使用客户不应该知道的数据,可以使用策略模式以避免暴露复杂的,预算法相关的数据结构。
  4. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支一如它们各自的策略类中一代替这些条件语句。

代码展示:

  1. //算法抽象
  2. public interface Transition {
  3. public String transition(String str);
  4. }
  1. //算法实现(转换为大写字母)
  2. public class UpperCaseTransition implements Transition{
  3. @Override
  4. public String transition(String str) {
  5. return str.toUpperCase();
  6. }
  7. }
  1. //算法实现(转换为小写字母)
  2. public class LowerCaseTransition implements Transition {
  3. @Override
  4. public String transition(String str) {
  5. return str.toLowerCase();
  6. }
  7. }
  1. //策略的外部封装
  2. public class Context implements Transition {
  3. private Transition transition;
  4. public Context(Transition transition) {
  5. this.transition = transition;
  6. }
  7. @Override
  8. public String transition(String str) {
  9. return transition.transition(str);
  10. }
  11. }
  1. //测试类
  2. public class Main {
  3. public static void main(String[] args) {
  4. Context context = new Context(new UpperCaseTransition());
  5. System.out.println(context.transition("abcdef"));
  6. Context context_1 = new Context(new LowerCaseTransition());
  7. System.out.println(context_1.transition("ABCDEF"));
  8. }
  9. }

运行结果:

ABCDEF
abcdef

策略模式的优点:

  1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
  2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或
    行为变得不可能。
  3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办
    法还要原始和落后。

缺点:

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
  2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。

十、观察者模式(Observer)

观察者模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
观察者模式提供给关联对象一种同步通信的手段,是某个对象与依赖它的其他对象之间保持状态同步。

角色:

  1. Subject(被观察者):被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
  2. ConcreteSubject:被观察者的具体实现。包含一些基本的属性状态及其他操作。
  3. Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
  4. ConcreteObserver:观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

代码示例:

  1. //被观察者
  2. public class Person extends Observable{
  3. private String name;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. this.setChanged();
  10. this.notifyObservers();
  11. }
  12. }
  1. //观察者
  2. public class MyObserver implements Observer {
  3. @Override
  4. public void update(Observable o, Object arg) {
  5. System.out.println("对象发生变化");
  6. }
  7. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Person person = new Person();
  5. //注册观察者
  6. person.addObserver(new MyObserver());
  7. person.setName("王二小");
  8. }
  9. }

观察者模式典型应用:

  1. 侦听时间驱动程序设计中的外部事件
  2. 侦听/件事某个对象的状态变化
  3. 发布者/订阅者(publicsher/subscriber)模型中,当一个外部事件被触发是,通知列表中的订阅者。

适用性:

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以独立地改变和复用。
  2. 当对一个对象那个的改变需要同时改变其他对象,而不知道具体对象有待改变,
  3. 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。

十一、 享元模式(Flyweight)

享元模式是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。

角色:

  1. 抽象享元角色: 所有具体享元类的父类,规定一些需要实现的公共接口。
  2. 具体享元角色: 抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
  3. 享元工厂角色: 负责创建和管理享元角色。

适用性:

  1. 一个程序使用的大量的对象。
  2. 完全由于使用大量对象,造成很大的存储开销。
  3. 对象的大多数状态都可以变为外部状态。

代码示例:
(本例中没有抽象享元角色)

  1. //具体享元角色
  2. public class MyCharacter {
  3. private char mychar;
  4. public MyCharacter(char mychar ) {
  5. this.mychar = mychar;
  6. }
  7. public void display(){
  8. System.out.println(mychar);
  9. }
  10. }
  1. //享元工厂角色
  2. public class MyCharacterFactory {
  3. private Map<Character,MyCharacter> pool;
  4. public MyCharacterFactory() {
  5. pool = new HashMap<Character,MyCharacter>();
  6. }
  7. //享元模式核心内容
  8. public MyCharacter getMyCharacter(Character character){
  9. MyCharacter mychar = pool.get(character);
  10. if(mychar == null){
  11. mychar = new MyCharacter(character);
  12. pool.put(character, mychar);
  13. }
  14. return mychar;
  15. }
  16. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. //创建工厂
  5. MyCharacterFactory mcf = new MyCharacterFactory();
  6. //从工厂中取出
  7. MyCharacter myChar1 = mcf.getMyCharacter('a');
  8. MyCharacter myChar2 = mcf.getMyCharacter('b');
  9. MyCharacter myChar3 = mcf.getMyCharacter('a');
  10. myChar1.display();
  11. myChar2.display();
  12. myChar3.display();
  13. System.out.println(myChar1.hashCode() + " " + myChar2.hashCode() + " " + myChar3.hashCode());
  14. }
  15. }

运行结果:(结果说明我们创建的myChar1和myChar3是同一个对象)

a
b
a
705927765 366712642 705927765

十二、 代理模式(proxy)

代理模式是结构性模式之一,它可以为其他对象提供一种代理以控制对这个对象的一种访问。
所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。

角色:

  1. subject(抽象主题角色):真实主题与代理主题的共同接口。
  2. RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
  3. Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。

适用性:

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式,下面是一些可以使用Proxy模式常见情况:
1. 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表

代码演示:

  1. //抽象主题角色:
  2. public interface Subject {
  3. public void sailBook();
  4. }
  1. //真实主题角色
  2. public class RealSubject implements Subject {
  3. @Override
  4. public void sailBook() {
  5. System.out.println("买书");
  6. }
  7. }
  1. //代理主题角色
  2. public class ProxySubject implements Subject {
  3. private RealSubject realSubject;
  4. public ProxySubject(RealSubject realSubject) {
  5. this.realSubject = realSubject;
  6. }
  7. public void Discount(){
  8. System.out.println("打折");
  9. }
  10. public void Vouchers(){
  11. System.out.println("赠送代金券");
  12. }
  13. @Override
  14. public void sailBook() {
  15. this.Discount();
  16. if(this.realSubject == null){
  17. realSubject = new RealSubject();
  18. }
  19. realSubject.sailBook();
  20. this.Vouchers();
  21. }
  22. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. RealSubject realSubject = new RealSubject();
  5. ProxySubject ps = new ProxySubject(realSubject);
  6. ps.sailBook();
  7. }
  8. }

运行结果:

打折
买书
赠送代金券


动态代理
代码示例:

  1. //抽象主题角色:
  2. public interface Subject {
  3. public void sailBook();
  4. }
  1. //真实主题角色
  2. public class RealSubject implements Subject {
  3. @Override
  4. public void sailBook() {
  5. System.out.println("买书");
  6. }
  7. }
  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. public class MyHandler implements InvocationHandler {
  4. private RealSubject realSubject;
  5. public void setRealSubject(RealSubject realSubject) {
  6. this.realSubject = realSubject;
  7. }
  8. public void Discount(){
  9. System.out.println("打折");
  10. }
  11. public void Vouchers(){
  12. System.out.println("赠送代金券");
  13. }
  14. @Override
  15. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  16. Object result = null;
  17. Discount();
  18. result = method.invoke(realSubject, args);
  19. Vouchers();
  20. return result;
  21. }
  22. }
  1. //测试函数
  2. import java.lang.reflect.Proxy;
  3. public class Main {
  4. public static void main(String[] args) {
  5. RealSubject realSubject = new RealSubject();
  6. MyHandler myHandler = new MyHandler();
  7. myHandler.setRealSubject(realSubject);
  8. Subject proxySubject =
  9. (Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
  10. realSubject.getClass().getInterfaces(), myHandler);
  11. proxySubject.sailBook();
  12. }
  13. }

十三、 外观模式(Facade)

外观模式为一组具有类似功能的类群,比如类库、子系统等等,提供一个一致的简单界面,这个一致的简单界面被称作facade。

适用性:

当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得也来越复杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具有可重用性,也跟你容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来了一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。

客户程序与抽象类的和实现部分之间存在很大的依赖性。引入facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间相互依赖的,你可以让它们仅通过facade进行通讯,从而简化它们之间的依赖关系。

角色:

  1. Facade:为调用方定义简单的调用接口。
  2. Clients:调用者。通过Facade接口调用提供某功能的内部类群。
  3. Packages:功能提供者,指提供功能的类群、模块、或者子系统。

代码示例:

  1. //功能提供者
  2. public class SystemA {
  3. /**
  4. * A子系统实现功能
  5. */
  6. public void doSomething(){
  7. System.out.println("实现A子系统功能");
  8. }
  9. }
  1. //功能提供者
  2. public class SystemB {
  3. /**
  4. * B子系统实现功能
  5. */
  6. public void doSomething(){
  7. System.out.println("实现B子系统功能");
  8. }
  9. }
  1. //Facade
  2. public class Facade {
  3. private SystemA systemA;
  4. private SystemB systemB;
  5. public Facade() {
  6. systemA = new SystemA();
  7. systemB = new SystemB();
  8. }
  9. public void doSomething(){
  10. this.systemA.doSomething();
  11. this.systemB.doSomething();
  12. }
  13. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. //常规方法
  5. //实现A子系统功能
  6. SystemA systemA = new SystemA();
  7. systemA.doSomething();
  8. //实现B子系统功能
  9. SystemB systemB = new SystemB();
  10. systemB.doSomething();
  11. //外观模式
  12. Facade facade = new Facade();
  13. facade.doSomething();
  14. }
  15. }

十四、 组合模式(Composite)

组合模式是构造型的设计模式之一,通过递归手段来构造树形的对象结构,并可以通过一个对象来访问整个对象树。

角色:

  1. component(树形结构的节点抽象)
    • 为所有的对象定义统一的接口。(公共属性,行为等的定义)
    • 提供管理子节点对象的接口方法
    • 【可选】提供管理父节点对象的接口方法
  2. Leaf(属性结构的叶节点)
    • Component的实现子类
  3. Composite(属性结构的枝节点)
    • Component的实现子类

适用性:

  • 你想表示对象的部分-整体结构层次
  • 你希望用户忽略组合对象与单个对象的不同,用户将统一的使用组合机构中的所有对象

代码示例

  1. //Component 树形结构的节点抽象
  2. /**
  3. * 文件节点抽象(是文件和目录的父类)
  4. * @author lvbiao
  5. *
  6. */
  7. public interface IFile {
  8. //显示文件夹或文件的名称
  9. public void display();
  10. //添加
  11. public boolean add(IFile iFile);
  12. //获得子节点
  13. public List<IFile> getChild();
  14. }
  1. // Leaf(属性结构的叶节点)
  2. public class File implements IFile {
  3. private String name;
  4. public File(String name) {
  5. this.name = name;
  6. }
  7. @Override
  8. public void display() {
  9. System.out.println(name);
  10. }
  11. @Override
  12. public boolean add(IFile iFile) {
  13. return false;
  14. }
  15. @Override
  16. public List<IFile> getChild() {
  17. return null;
  18. }
  19. }
  1. Composite(属性结构的枝节点)
  2. public class Folder implements IFile {
  3. private String name;
  4. private List<IFile> children;
  5. public Folder(String name) {
  6. this.name = name;
  7. children = new ArrayList<IFile>();
  8. }
  9. @Override
  10. public void display() {
  11. System.out.println(name);
  12. }
  13. @Override
  14. public boolean add(IFile iFile) {
  15. return children.add(iFile);
  16. }
  17. public boolean remove(IFile iFile){
  18. return children.remove(iFile);
  19. }
  20. @Override
  21. public List<IFile> getChild() {
  22. return children;
  23. }
  24. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. //c盘
  5. Folder rootFolder = new Folder("C:");
  6. //1.txt
  7. File File_1 = new File("1.txt");
  8. //一级目录
  9. Folder Folder_1 = new Folder("一级文件夹");
  10. rootFolder.add(File_1);
  11. rootFolder.add(File_1);
  12. rootFolder.add(Folder_1);
  13. Folder_1.add(new Folder("二级文件夹"));
  14. Folder_1.add(new Folder("二级文件夹"));
  15. Folder_1.add(new File("2.txt"));
  16. rootFolder.add(File_1);
  17. displayTree(rootFolder,0);
  18. }
  19. public static void displayTree(IFile rootFolder,int deep){
  20. for(int i = 0; i < deep; i++){
  21. System.out.print("++");
  22. }
  23. //显示自身的名称
  24. rootFolder.display();
  25. //获得子树
  26. List<IFile> children = rootFolder.getChild();
  27. //遍历子树
  28. for(IFile file : children){
  29. if(file instanceof File){
  30. for(int i = 0; i <= deep; i++){
  31. System.out.print("++");
  32. }
  33. file.display();
  34. }else {
  35. displayTree(file,deep+1);
  36. }
  37. }
  38. }
  39. }

运行结果:

C:
++1.txt
++1.txt
++一级文件夹
++++二级文件夹
++++二级文件夹
++++2.txt
++1.txt

十五、 桥接模式(Bridge)

桥接模式是构造型设计模式之一。桥接模式是基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象与行为实现分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。

适用性:

  • 你不希望再抽象和它的实现部分之间有一个固定的绑定关系,希望可以在程序运行时刻实现部分应该可以被选择或者切换
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩展,这是交接模式是你可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充。
  • 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不需要重新编译。
  • 你想对客户完全隐藏抽象的实现部分。
  • 有许多类要生成,这样一种类层次结构说明你必须将一个对象分解成两个部分。
  • 你想在多个对象之间共享实现(可能使用引用计数),单同时要求客户并不知道这一点。

角色:

  1. Abstraction抽象类接口(接口或抽象类):
    维护对行为实现(Implementor)的引用
  2. Refined Abstraction:
    Abstraction子类
  3. Implementor:
    行为实现类接口 (Abstraction接口定义了基于Implementor接口的更高层次的操作)
  4. ConcreteImplementor:
    Implementor子类

代码实现:

  1. //Abstraction抽象类接口
  2. public abstract class Car {
  3. private Engine engine;
  4. public Car(Engine engine) {
  5. this.engine = engine;
  6. }
  7. public Engine getEngine() {
  8. return engine;
  9. }
  10. public void setEngine(Engine engine) {
  11. this.engine = engine;
  12. }
  13. public abstract void installEngine();
  14. }
  1. //Abstraction子类
  2. public class Bus extends Car {
  3. public Bus(Engine engine) {
  4. super(engine);
  5. }
  6. @Override
  7. public void installEngine() {
  8. System.out.print("Bus: ");
  9. super.getEngine().installEngine();
  10. }
  11. }
  1. //Implementor
  2. public interface Engine {
  3. public void installEngine();
  4. }
  1. //Implementor子类
  2. public class Engine2000 implements Engine{
  3. @Override
  4. public void installEngine() {
  5. System.out.println("安装cc2000发动机");
  6. }
  7. }
  1. //Implementor子类
  2. public class Engine2200 implements Engine{
  3. @Override
  4. public void installEngine() {
  5. System.out.println("安装cc2200发动机");
  6. }
  7. }
  1. //测试函数
  2. public class Main{
  3. public static void main(String[] args) {
  4. Engine engine2000 = new Engine2000();
  5. Car bus = new Bus(engine2000);
  6. bus.installEngine();
  7. }
  8. }

运行结果:

Bus: 安装cc2000发动机

十六、 适配器模式(Adapter)

适配器模式是构造型模式之一,通过适配器模式可以改变已有类的接口形式。

适用性:

  • 你想使用一个已经存在的类,而它的接口不符合你的需求。
  • 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作。
  • 你想使用一些已经存在的子类,但是不可能对每一个都进行子类化已匹配他们的接口,对象适配器可以适配它的父接口。

实现方法:

  1. 通过继承实现
  2. 通过委让实现

通过继承实现适配器模式实例:

  1. //已有类
  2. public class Adaptee {
  3. public void oldMethod(){
  4. System.out.println("使用220V电压");
  5. }
  6. }
  1. //适配器接口
  2. public interface Target {
  3. public void requirdMethod();
  4. }
  1. //适配器
  2. public class Adapter extends Adaptee implements Target{
  3. @Override
  4. public void requirdMethod() {
  5. System.out.println("在这里调用:");
  6. super.oldMethod();
  7. }
  8. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Target adapter = new Adapter();
  5. adapter.requirdMethod();
  6. }
  7. }

运行结果:

在这里调用:
使用220V电压


通过委让实现适配器模式实例:

已有类和适配器接口同上

  1. //适配器
  2. public class Adapter2 extends Adaptee implements Target{
  3. private Adaptee adaptee;
  4. public Adapter2(Adaptee adaptee) {
  5. this.adaptee = adaptee;
  6. }
  7. @Override
  8. public void requirdMethod() {
  9. System.out.println("在这里调用:");
  10. adaptee.oldMethod();
  11. }
  12. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Target adapter2 = new Adapter2(new Adaptee());
  5. adapter2.requirdMethod();
  6. }
  7. }

运行结果:

在这里调用:
使用220V电压

十七、 解释器模式(Interpreter)

解释器模式是行为模式之一,它是一种特殊的设计模式,它建立一个解释器,对于特定的据算计程序设计语言,用来解释预先定义的文法。简单的说解释器模式是一种简单的语法解释器架构。

适用性:

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树,可是用解释器模式。而当存在以下情况是该模式效果最好。
1. 该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是最好的选择。他们无需构建抽象语法树即可解释表达式,这样可以节省空间而且还可能节省时间。
效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下,转换器仍可以用解释器模式实现,该模式仍是有用的。

角色:

  1. Context 解释器上下文环境类:用来存储解释器的上下文环境,比如需要解释的文法等。
  2. AbstractExpression 解释器抽象类。
  3. ConcreteExpression 解释器具体实现类。

具体代码实现:

  1. //Context 解释器上下文环境类
  2. public class Context {
  3. private String input;
  4. private int output;
  5. public Context(String input) {
  6. this.input = input;
  7. }
  8. public String getInput() {
  9. return input;
  10. }
  11. public void setInput(String input) {
  12. this.input = input;
  13. }
  14. public int getOutput() {
  15. return output;
  16. }
  17. public void setOutput(int output) {
  18. this.output = output;
  19. }
  20. }
  1. // AbstractExpression 解释器抽象类
  2. public abstract class Expression {
  3. public abstract void Interpret(Context context);
  4. }
  1. // ConcreteExpression 解释器具体实现类
  2. public class PlusExpression extends Expression{
  3. @Override
  4. public void Interpret(Context context) {
  5. //提示信息
  6. System.out.println("自动递增");
  7. //获得上下文环境
  8. String input = context.getInput();
  9. //进行类型转换
  10. int intInput = Integer.parseInt(input);
  11. //进行递增
  12. ++ intInput;
  13. //对上下文重新进行赋值
  14. context.setInput(intInput+"");
  15. context.setOutput(intInput);
  16. }
  17. }
  1. // ConcreteExpression 解释器具体实现类
  2. public class MinusExperssion extends Expression{
  3. @Override
  4. public void Interpret(Context context) {
  5. //提示信息
  6. System.out.println("自动递减");
  7. //获得上下文环境
  8. String input = context.getInput();
  9. //进行类型转换
  10. int intInput = Integer.parseInt(input);
  11. //进行递增
  12. -- intInput;
  13. //对上下文重新进行赋值
  14. context.setInput(intInput+"");
  15. context.setOutput(intInput);
  16. }
  17. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. String number = "10";
  5. Context context = new Context(number);
  6. Expression plusExperssion = new PlusExpression();
  7. plusExperssion.Interpret(context);
  8. System.out.println(context.getOutput());
  9. Expression minusExperssion = new MinusExperssion();
  10. minusExperssion.Interpret(context);
  11. System.out.println(context.getOutput());
  12. }
  13. }

运行结果:

自动递增
11
自动递增
10

十八、 中介者模式(Mediator)

中介者模式是行为模式的一种,在中介者模式中,类的交互行为被统一放在中介者的对象中,对象通过中介者对象同其他对象交互,中介者对象起着控制器的作用。

适用性:

  • 一组对象已定义但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

角色:

mediator 中介者类的抽象父类。
concreteMediator 具体的中介者类。
colleague 关联类的抽象父类。
concreteColleague 具体的关联类。

代码演示:

  1. //mediator 中介者类的抽象父类
  2. public abstract class Mediator {
  3. protected Man man;
  4. protected Woman woman;
  5. public Man getMan() {
  6. return man;
  7. }
  8. public void setMan(Man man) {
  9. this.man = man;
  10. }
  11. public Woman getWoman() {
  12. return woman;
  13. }
  14. public void setWoman(Woman woman) {
  15. this.woman = woman;
  16. }
  17. public abstract void getPartner(Person person);
  18. }
  1. //concreteMediator 具体的中介者类
  2. public class ConcreteMediator extends Mediator{
  3. @Override
  4. public void getPartner(Person person) {
  5. //设置搭档
  6. if(person instanceof Man){
  7. this.setMan((Man)person);
  8. }else{
  9. this.setWoman((Woman)person);
  10. }
  11. //进行匹配
  12. if(man == null || woman == null){
  13. System.out.println("我不是同性恋");
  14. }else {
  15. if(man.getCondition() == woman.getCondition()){
  16. System.out.println(man.getName() + "和" + woman.getName() + "绝配");
  17. } else{
  18. System.out.println(man.getName() + "和" + woman.getName() + "不相配");
  19. }
  20. }
  21. }
  22. }
  1. //colleague 关联类的抽象父类
  2. public abstract class Person {
  3. private String name;
  4. private int condition;
  5. private Mediator mediator;
  6. public Person(String name, int condition,Mediator mediator) {
  7. this.name = name;
  8. this.condition = condition;
  9. this.mediator = mediator;
  10. }
  11. public Mediator getMediator() {
  12. return mediator;
  13. }
  14. public void setMediator(Mediator mediator) {
  15. this.mediator = mediator;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public int getCondition() {
  24. return condition;
  25. }
  26. public void setCondition(int condition) {
  27. this.condition = condition;
  28. }
  29. public abstract void getPartner(Person person);
  30. }
  1. //concreteColleague 具体的关联类
  2. public class Man extends Person{
  3. public Man(String name, int condition,Mediator mediator) {
  4. super(name, condition, mediator);
  5. }
  6. @Override
  7. public void getPartner(Person person) {
  8. this.getMediator().setMan(this);
  9. this.getMediator().getPartner(person);
  10. }
  11. }
  1. //concreteColleague 具体的关联类
  2. public class Woman extends Person{
  3. public Woman(String name, int condition,Mediator mediator) {
  4. super(name, condition, mediator);
  5. }
  6. @Override
  7. public void getPartner(Person person) {
  8. this.getMediator().setWoman(this);
  9. this.getMediator().getPartner(person);
  10. }
  11. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Mediator mediator = new ConcreteMediator();
  5. Person XiaoMing = new Man("小明",5,mediator);
  6. Person XiaoFang = new Woman("小芳",5,mediator);
  7. XiaoMing.getPartner(XiaoFang);
  8. }
  9. }

十九、 职责链模式(Chain of Responsibility)

职责链模式也叫职责连锁模式,是行为模式的一种,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间像链条一样紧密相连,所以称为职责链模式。

要实现职责链模式,需要满足该模式的基本条件:

  1. 对象链的组织,需要将某任务的所有职责执行对象以链的形式加以组织。
  2. 消息或请求的传递,将消息或请求沿着对象链传递,以让处于对象链中的对象得到处理机会。
  3. 处于对象链中的对象的职责分配,不同的对象完成不同的职责。
  4. 任务完成。处于对象链的末尾的对象结束任务,并停止消息或请求的继续传递。

角色:

Handler 处理类的抽象父类。
concreteHandler 具体的处理类。

优点:

  1. 责任的分担。每个类只需要处理自己该处理的工作(不该处理的传递给下一个对象完成),明确各类的责任范围,符合类的最小封装原则。
  2. 可以根据需要重新组合工作流程。如工作流程发生变化,可以重新分配对象链便可适应新的工作流程。
  3. 类与类之间可以以松耦合的形式加以组织。

缺点:

因为处理以链的形式在对象间传递消息,根据方式不同,有可能会影响处理的速度。

适用性:

  1. 有多个的对象可以处理一个请求,那个对象处理该请求运行时刻自动确定。
    1. 你想在不明确接受者的情况下,向多个对象中的一个提交一个请求。
    2. 可以处理一个请求的对象集合应被动态指定。

代码示例:

  1. //处理类的抽象父类
  2. public abstract class CarHandler {
  3. protected CarHandler carHandler;
  4. public CarHandler setNextCarHandler(CarHandler carHandler){
  5. this.carHandler = carHandler;
  6. return this.carHandler;
  7. }
  8. public abstract void HandCar();
  9. }
  1. //具体的处理类
  2. public class CarHeadHandler extends CarHandler {
  3. @Override
  4. public void HandCar() {
  5. System.out.println("组装车头");
  6. if(this.carHandler != null){
  7. this.carHandler.HandCar();
  8. }
  9. }
  10. }
  1. //具体的处理类
  2. public class CarBodyHandler extends CarHandler {
  3. @Override
  4. public void HandCar() {
  5. System.out.println("组装车身");
  6. if(this.carHandler != null){
  7. this.carHandler.HandCar();
  8. }
  9. }
  10. }
  1. //具体的处理类
  2. public class CarTailHandler extends CarHandler {
  3. @Override
  4. public void HandCar() {
  5. System.out.println("组装车尾");
  6. }
  7. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. CarHandler carHead = new CarHeadHandler();
  5. CarHandler carBody = new CarBodyHandler();
  6. CarHandler carTail = new CarTailHandler();
  7. carHead.setNextCarHandler(carBody).setNextCarHandler(carTail);
  8. carHead.HandCar();
  9. }
  10. }

运行结果:

组装车头
组装车身
组装车尾

二十、 迭代模式(Iterator)

迭代模式是行为模式之一,它把对容器中包含的内部对象的访问委让给外部类,使用Iterator(遍历)按顺序进行遍历访问的设计模式。

不使用迭代模式时存在的问题:

  1. 由容器自己实现顺序遍历,直接在容器类里直接添加顺序遍历方法。
  2. 让调用者自己实现遍历,直接暴露数据细节给外部。
    以上两种方法都可以实现对容器的遍历,但是这样容器承担的太多的功能,一方面 需要提供添加删除等本身应有的功能,一方面还需要提供遍历访问功能。;往往容器在实现遍历的过程中,需要保存遍历状态,当根元素的添加删除等功能夹杂在一起,很容易引起混乱和程序运行错误。

适用性:

  1. 访问一个聚合对象的内容而无需暴露它的内部接口。
  2. 支持对聚合对象的多种遍历。
  3. 为遍历不同的聚合结构提供一个统一的接口(即支持多台迭代)。

角色:

Iterator(迭代器接口): 该接口必须定义实现迭代功能的最小定义方法集比如提供hasNext()和next()方法。
ConcreteIterator(迭代器实现类):迭代器接口Iterator的实现类。可以根据具体情况加以实现。
Aggregate(容器接口): 定义基本功能以及提供类似Iterator iterator()的方法。
concreteAggregate(容器实现类): 容器接口的实现类。必须实现Iterator iterator()方法。

代码示例:

  1. //Iterator(迭代器接口):
  2. public interface Iterator {
  3. public boolean hasNext();
  4. public Object next();
  5. }
  1. //ConcreteIterator(迭代器实现类)
  2. public class ConcreteIterator implements Iterator {
  3. private List<Object> list = new ArrayList<>();
  4. private int cursor = 0;
  5. public ConcreteIterator(List<Object> list) {
  6. this.list = list;
  7. }
  8. @Override
  9. public boolean hasNext() {
  10. if(cursor >= list.size()){
  11. return false;
  12. }
  13. return true;
  14. }
  15. @Override
  16. public Object next() {
  17. Object obj = null;
  18. if(this.hasNext()){
  19. obj = this.list.get(cursor++);
  20. }
  21. return obj;
  22. }
  23. }
  1. //Aggregate(容器接口)
  2. public interface Aggregate {
  3. public void add(Object obj);
  4. public void remove(Object obj);
  5. public Iterator iterator();
  6. }
  1. //concreteAggregate(容器实现类)
  2. public class ConcreteAggregate implements Aggregate{
  3. private List<Object> list = new ArrayList<>();
  4. @Override
  5. public void add(Object obj) {
  6. list.add(obj);
  7. }
  8. @Override
  9. public void remove(Object obj) {
  10. list.remove(obj);
  11. }
  12. @Override
  13. public Iterator iterator() {
  14. return new ConcreteIterator(list);
  15. }
  16. }
  1. //Object
  2. public class Person {
  3. private String name;
  4. private int age;
  5. public Person(String name, int age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. }
  10. //省略get、set方法
  1. //测试类
  2. public class Main {
  3. public static void main(String[] args) {
  4. Person person1 = new Person("小明",22);
  5. Person person2 = new Person("小王",21);
  6. Person person3 = new Person("小芳",23);
  7. Aggregate agg = new ConcreteAggregate();
  8. agg.add(person1);
  9. agg.add(person2);
  10. agg.add(person3);
  11. Iterator ite = agg.iterator();
  12. while(ite.hasNext()){
  13. Person person = (Person) ite.next();
  14. person.show();
  15. }
  16. }
  17. }

运行结果:

姓名:小明 年龄:22
姓名:小王 年龄:21
姓名:小芳 年龄:23

二十一、 模板方法模式(Template Method)

模板方法模式是行为模式的一种,它把具有特定步骤算法中的某些必要的处理委让给抽象方法,通过子类继承对抽象方法的不同实现改变整个算法的行为。

角色:

AbstractClass: 抽象类的父类
ConcreteClass: 具体的实现子类
templateMethod(): 模板方法

应用场景:

  • 具有统一的操作步骤或操作过程。
  • 具有不同的操作细节。
  • 存在多个具有同样操作步骤的引用场景,但某些具体的操作细节却各不相同。

适用性:

  1. 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  2. 各个子类公共的行为应该被提取出来并集中到一个公共父类中以避免代码重复。

代码示例

  1. //抽象类的父类
  2. public abstract class MakeCar {
  3. //组装车头
  4. public abstract void makeHead();
  5. //组装车身
  6. public abstract void makeBody();
  7. //组装车尾
  8. public abstract void makeTail();
  9. //核心内容,这就是模板方法
  10. public void make(){
  11. this.makeHead();
  12. this.makeBody();
  13. this.makeTail();
  14. }
  15. }
  1. //具体的实现子类
  2. public class MakeBus extends MakeCar {
  3. @Override
  4. public void makeHead() {
  5. System.out.println("bus: 组装车头");
  6. }
  7. @Override
  8. public void makeBody() {
  9. System.out.println("bus: 组装车身");
  10. }
  11. @Override
  12. public void makeTail() {
  13. System.out.println("bus: 组装车尾");
  14. }
  15. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. MakeCar bus = new MakeBus();
  5. bus.make();
  6. }
  7. }

运行结果:

bus: 组装车头
bus: 组装车身
bus: 组装车尾

二十二、 备忘录模式(Memento)

备忘录模式是行为模式之一,它的作用是保存对象内部状态,并在需要的时候恢复对象以前的状态。

角色:

Originator(原生者): 需要被保存状态以便恢复的那个对象。
Memento(备忘录): 该对象由Originator创建,主要用来保存Originator的内部状态。
Caretaker(管理者): 负责在适当的时间保存/恢复Originator对象的状态。

应用场景:

如果一个对象需要保存并可以通过undo或roback等操作恢复到以前的状态时,可以使用Memento模式。
1. 一个类需要保存它的对象的状态(相当于Originator角色)
2. 设计一个类,该类只是用来保存上述对象的状态(相当于Memento角色)
3. 需要的时候,Caretaker角色要求Originator返回一个Memento并加以保存
4. undo或rollback操作时,通过Caretaker保存的Memento恢复Originator对象的状态

适用性:

  • 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
  • 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

代码示例:

  1. //Originator(原生者)
  2. public class Person {
  3. private String name;
  4. private String sex;
  5. private int age;
  6. public Person(String name, String sex, int age) {
  7. this.name = name;
  8. this.sex = sex;
  9. this.age = age;
  10. }
  11. //省略get/set方法
  12. public void display(){
  13. System.out.println("姓名:" + name + " 性别:" + sex + " 年龄:" + age);
  14. }
  15. //创建备份
  16. public Memento createMemento(){
  17. return new Memento(this.name, this.sex, this.age);
  18. }
  19. //恢复备份
  20. public void getMemento(Memento memento){
  21. this.name = memento.getName();
  22. this.sex = memento.getSex();
  23. this.age = memento.getAge();
  24. }
  25. }
  1. //Memento(备忘录)
  2. public class Memento {
  3. private String name;
  4. private String sex;
  5. private int age;
  6. public Memento() {
  7. }
  8. public Memento(String name, String sex, int age) {
  9. this.name = name;
  10. this.sex = sex;
  11. this.age = age;
  12. }
  13. //get、set方法省略
  14. }
  1. //Caretaker(管理者)
  2. public class CreateTaker {
  3. private Memento memento;
  4. public CreateTaker(Memento memento) {
  5. this.memento = memento;
  6. }
  7. //get、set方法省略
  8. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. //原始数据
  5. Person person = new Person("小王", "男", 24);
  6. person.display();
  7. //进行备份
  8. CreateTaker ct = new CreateTaker(person.createMemento());
  9. //修改数据
  10. person.setName("小李");
  11. person.setSex("女");
  12. person.setAge(20);
  13. person.display();
  14. //恢复备份
  15. person.getMemento(ct.getMemento());
  16. person.display();
  17. }
  18. }

运行结果:

姓名:小王 性别:男 年龄:24
姓名:小李 性别:女 年龄:20
姓名:小王 性别:男 年龄:24

二十三、 状态模式(satate)

状态模式是行为模式的一种,状态模式允许通过改变对象内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。

角色:

Context:用户对象: 拥有一个State类型的成员,以标识对象的当前状态;
State:接口或基类封装与Context的特定状态相关的行为;
ConcreteState:接口实现类或子类实现了一个与Context某个状态相关的行为。

引用场景:

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况,把状态的判断逻辑转译到表现不同状态的一些列类当中,可以把复杂的判断逻辑简单化。

适用性:

一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态,这个状态通常用一个或多个美剧常量表示,通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中,这使得你可以根据自身的情况将对象的状态作为一个对象,这个对象可以不依赖于其他对象而独立存在。

代码示例:

  1. //用户对象
  2. public class Person {
  3. private int time;
  4. private State state;
  5. //省略get、set方法
  6. public void doSomething(){
  7. state.doSomething(this);
  8. }
  9. }
  1. //State接口
  2. public interface State {
  3. public void doSomething(Person person);
  4. }
  1. //ConcreteState
  2. public class BreakfastState implements State{
  3. @Override
  4. public void doSomething(Person person) {
  5. if(person.getTime() == 7){
  6. System.out.println("吃早餐");
  7. } else{
  8. person.setState(new LunchState());
  9. person.doSomething();
  10. }
  11. }
  12. }
  1. //ConcreteState
  2. public class LunchState implements State{
  3. @Override
  4. public void doSomething(Person person) {
  5. if(person.getTime() == 12){
  6. System.out.println("吃午餐");
  7. } else{
  8. person.setState(new DinnerState());
  9. person.doSomething();
  10. }
  11. }
  12. }
  1. //ConcreteState
  2. public class DinnerState implements State{
  3. @Override
  4. public void doSomething(Person person) {
  5. if(person.getTime() == 18){
  6. System.out.println("吃晚餐");
  7. } else{
  8. person.setState(new NoState());
  9. person.doSomething();
  10. }
  11. }
  12. }
  1. //ConcreteState
  2. public class NoState implements State{
  3. @Override
  4. public void doSomething(Person person) {
  5. if(person.getTime() == 7){
  6. person.setState(new BreakfastState());
  7. person.doSomething();
  8. } else{
  9. System.out.println(person.getTime() + "点未定义");
  10. }
  11. }
  12. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Person person = new Person();
  5. person.setState(new BreakfastState());
  6. person.setTime(7);
  7. person.doSomething();
  8. person.setTime(12);
  9. person.doSomething();
  10. person.setTime(18);
  11. person.doSomething();
  12. person.setTime(8);
  13. person.doSomething();
  14. person.setTime(7);
  15. person.doSomething();
  16. }
  17. }

运行结果:

吃早餐
吃午餐
吃晚餐
8点未定义
吃早餐

二十四、 命令模式(command)

命令模式是行为设计模式的一种,是将一个请求封装为一个对象,从而是你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销操作。

角色:

Command : Command抽象类。
ConcreteCommand: Command的具体实现类。
Receiver: 需要被调用的目标对象。
Invorker: 通过Invorker执行Command对象。

应用场景:

在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
- 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
- 调用前后需要对调用参数进行某些处理。
- 调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。

适用性:

抽象出待执行的动作以参数化某对象,你可用过程语言中的回调函数表达这种参数化机制,所谓回调函数是指函数现在某处注册,而它在稍后某个需要的时候被调用。Command模式是回调机制的一个面向对象的替代品。
在不同的时刻指定、排列和执行请求。一个Command对象可以有一个与初始请求无关的生存期。如果一个请求的接受者可用一种与地址空间无关的生存期。如果一个请求的接受者可用一种与地址空间无关的表达式,那么就可将该命令的命令对象传送给另一个不同的进程并在哪儿实现请求。
支持取消操作,Command的Excute操作可在实时操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。
Command接口必须添加一个UNexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现重数不限的“取消”和“重做”。
支持修改日志,这样当系统崩溃是,这些修改可以被重做一遍,在Command借口总添加装载操作和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作执行它们。
用构建在原操作上的高层操作构造一个系统。一个事物封装了对数据的一组变动。Command模式提供了对事物进行建模的方法。
Command有一个公共的接口,使得你可以用一种方式调用所有的事物。同时使用该模式也抑郁添加新事物加以扩展系统。

代码示例:

  1. //Receiver: 需要被调用的目标对象
  2. public class Receiver {
  3. //假设方法很复杂,不能直接调用
  4. public void StudyJava(){
  5. System.out.println("学习Java");
  6. }
  7. //假设方法很复杂,不能直接调用
  8. public void StudyPython(){
  9. System.out.println("学习Python");
  10. }
  11. }
  1. //Command : Command抽象类
  2. public abstract class Command {
  3. private Receiver receiver;
  4. public Command(Receiver receiver) {
  5. super();
  6. this.receiver = receiver;
  7. }
  8. public Receiver getReceiver() {
  9. return receiver;
  10. }
  11. public void setReceiver(Receiver receiver) {
  12. this.receiver = receiver;
  13. }
  14. public abstract void Study();
  15. }
  1. //ConcreteCommand: Command的具体实现类。
  2. public class CommandJava extends Command {
  3. public CommandJava(Receiver receiver) {
  4. super(receiver);
  5. }
  6. @Override
  7. public void Study() {
  8. System.out.println("Java----还可以在这里进行其他操作,比如日志,缓存,记录历史操作");
  9. this.getReceiver().StudyJava();
  10. }
  11. }
  1. //ConcreteCommand: Command的具体实现类。
  2. public class CommandPython extends Command {
  3. public CommandPython(Receiver receiver) {
  4. super(receiver);
  5. }
  6. @Override
  7. public void Study() {
  8. System.out.println("Python----还可以在这里进行其他操作,比如日志,缓存,记录历史操作");
  9. this.getReceiver().StudyPython();
  10. }
  11. }
  1. //Invorker: 通过Invorker执行Command对象。
  2. public class Invoker {
  3. private Command command;
  4. public Invoker(Command command) {
  5. this.command = command;
  6. }
  7. public Command getCommand() {
  8. return command;
  9. }
  10. public void setCommand(Command command) {
  11. this.command = command;
  12. }
  13. public void study(){
  14. this.command.Study();
  15. }
  16. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. Receiver receiver = new Receiver();
  5. Command commandJava = new CommandJava(receiver);
  6. Command commandPython = new CommandPython(receiver);
  7. Invoker invokerJava = new Invoker(commandJava);
  8. invokerJava.study();
  9. Invoker invokerPathon = new Invoker(commandPython);
  10. invokerPathon.study();
  11. }
  12. }

运行结果:

java----还可以在这里进行其他操作,比如日志,缓存,记录历史操作
学习Java
Python----还可以在这里进行其他操作,比如日志,缓存,记录历史操作
学习Python

二十五、 访问者模式(Visitor)

访问者模式是行为模式之一,它分离对象的数据和行为,使用访问者模式可以不修改已有类的情况下,增加新的操作。

角色:

  1. 访问者角色(Visitor):
    为该对象结构中具体元素角色声明一个访问操作接口。该操作接
    口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。
    这样访问者就可以通过该元素角色的特定接口直接访问它。
  2. 具体访问者角色(Concrete Visitor):
    实现每个由访问者角色(Visitor)声明的操作。
  3. 元素角色(Element):
    定义一个Accept操作,它以一个访问者为参数。
  4. 具体元素角色(Concrete Element):
    实现由元素角色提供的Accept操作。
    5) 对象结构角色(Object Structure):
    这是使用访问者模式必备的角色。它要具备以下特征:能枚举
    它的元素;可以提供一个高层的接口以允许该访问者访问它的元
    素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序
    集合。

代码示例:

  1. //元素角色(Element)
  2. public interface ParkElement {
  3. public void accpect(Visitor visitor);
  4. }
  1. //具体元素角色(Concrete Element)
  2. public class ParkA implements ParkElement{
  3. @Override
  4. public void accpect(Visitor visitorA) {
  5. visitorA.visit(this);
  6. }
  7. }
  1. //具体元素角色(Concrete Element)
  2. public class ParkB implements ParkElement{
  3. @Override
  4. public void accpect(Visitor visitorB) {
  5. visitorB.visit(this);
  6. }
  7. }
  1. // 对象结构角色(Object Structure)
  2. public class Park implements ParkElement{
  3. private ParkA parkA;
  4. private ParkB parkB;
  5. public Park(ParkA parkA, ParkB parkB) {
  6. super();
  7. this.parkA = parkA;
  8. this.parkB = parkB;
  9. }
  10. @Override
  11. public void accpect(Visitor visitor) {
  12. visitor.visit(this);
  13. visitor.visit(parkA);
  14. visitor.visit(parkB);
  15. }
  16. }
  1. //访问者角色(Visitor)
  2. public interface Visitor {
  3. public void visit(Park park);
  4. public void visit(ParkA parkA);
  5. public void visit(ParkB parkB);
  6. }
  1. //具体访问者角色(Concrete Visitor)
  2. public class VisitorA implements Visitor {
  3. @Override
  4. public void visit(Park park) {
  5. }
  6. @Override
  7. public void visit(ParkA parkA) {
  8. System.out.println("清洁工A: 负责公园A部分的卫生");
  9. }
  10. @Override
  11. public void visit(ParkB parkB) {
  12. }
  13. }
  1. //具体访问者角色(Concrete Visitor)
  2. public class VisitorB implements Visitor {
  3. @Override
  4. public void visit(Park park) {
  5. }
  6. @Override
  7. public void visit(ParkA parkA) {
  8. }
  9. @Override
  10. public void visit(ParkB parkB) {
  11. System.out.println("清洁工B: 负责公园B部分的卫生");
  12. }
  13. }
  1. /具体访问者角色(Concrete Visitor
  2. public class VisitorManager implements Visitor {
  3. @Override
  4. public void visit(Park park) {
  5. System.out.println("管理员: 负责整个公园的卫生检查");
  6. }
  7. @Override
  8. public void visit(ParkA parkA) {
  9. System.out.println("管理员: 负责公园A部分的卫生检查");
  10. }
  11. @Override
  12. public void visit(ParkB parkB) {
  13. System.out.println("管理员: 负责公园B部分的卫生检查");
  14. }
  15. }
  1. //测试函数
  2. public class Main {
  3. public static void main(String[] args) {
  4. ParkA parkA = new ParkA();
  5. ParkB parkB = new ParkB();
  6. Park park = new Park(parkA,parkB);
  7. Visitor visitorA = new VisitorA();
  8. Visitor visitorB = new VisitorB();
  9. Visitor visitor = new VisitorManager();
  10. parkA.accpect(visitorA);
  11. parkB.accpect(visitorB);
  12. park.accpect(visitor);
  13. }
  14. }

运行结果:

清洁工A: 负责公园A部分的卫生
清洁工B: 负责公园B部分的卫生
管理员: 负责整个公园的卫生检查
管理员: 负责公园A部分的卫生检查
管理员: 负责公园B部分的卫生检查

二十六、 七大设计原则

设计原则名称 定义
单一职责 一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类中。
开闭原则 软件实体应当对扩展开放,对修改关闭。
里氏替换原则 所有引用基类的地方必须能透明的使用其子类对象。
依赖倒置原则 高层模块不应该依赖底层的模块,它们都应该依赖抽象。抽象不应该依赖具体细节,具体细节应该依赖于抽象。
接口隔离原则 客户端不应该依赖那些它不需要的接口。
合成复用原则 优先使用对象组合,而不是使用继承来达到复用的目的。
迪米特法则 每个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注