No2.大话设计模式学习之工厂方法、建造者、观察者模式

No2.大话设计模式学习之工厂方法、建造者、观察者模式

2.设计模式-part2

  • 2.4 工厂方法模式

    collapsed:: true
    • 描述:工厂方法模式(Factory Method Pattern)是指定义一个用于创建对象的结构,让子类决定实例化哪个类,即类的实例化过程延迟到其子类
    • 核心点:客户端决定实例化哪一个工厂来实现功能类,即将[[简单工厂]]内部的逻辑判断移到客户端进行
    • 原则1:有明确的根据不同条件创造实例的计划时。将类类比为产品,产品具有系列/组合的形式,则使用者可以在不清楚类生产的具体过程及一个系列/组合的类包含的具体内容的情况下,使用一个系列的产品
    • 原则2:无法预知对象确切类别及其依赖关系时,工厂方法能将创建产品的代码与实际使用铲平的代码分离,从而能在不影响其他代码的情况下扩展产品创建的部分。
    • 原则3:希望用户能扩展软件库/框架的内部组件
    • 好处1:可以避免创建者和具体产品之间的紧密耦合;
    • 好处2:扩展性高,如果想增加一个新的产品,只需要扩展一个工厂类就可以;
    • 好处3:符合“开放封闭原则”,无需更改现有工厂类代码,就可以引入新的功能;
    • 好处4:符合“单一职责原则”,可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
    • 坏处1:代码可能变得复杂,因为需要引入许多类
    • eg:(大学生薛磊风在过去三年里一直在帮助孤寡老人,每周都去老人家里,为老人洗衣扫地、买米买油。有一次,他不幸受了伤,便委托他的两个同学继续去帮助老人,且不必提及任何人的名字,只需说是学雷锋做好事即可
      帮助老人是长期工作,三名“学雷锋的大学生”毕业后,也依然会以“社区志愿者”的名义继续学雷锋做好事。而老人其实不需要知道是谁来做好事,只需要知道是学雷锋的人来帮助就可以了)
      • 场景:先用简单工厂模式实现,但由于学雷锋的学生毕业后,会转变身份成为社区志愿者,此时若使用简单工厂模式会涉及到工厂类的修改,违背开放封闭原则。当我们使用工厂方法模式时,可以对学雷锋的学生和社区志愿者分别建立工厂类,让客户端决定实例化哪一个工厂类
      • 步骤:
        • 创建抽象类LetFeng,同时定义公共接口,即三种好事:
        • 定义方法Sweep()Wash()BuyRice()
        • 创建具体的做好事的类:学雷锋的大学生Undergraduate,及社区志愿者Volunteer,继承于抽象类LetFeng
        • 创建雷锋工厂类IFactory,再定义学雷锋的大学生工厂UndergraduateFactory和社区志愿者工厂VolunteerFactory继承于雷锋工厂,用于创建具体的对象。
      • 代码实现:
        • 首先创建抽象类LetFeng
        • public class LeiFeng {
              public void sweep() {
                  System.out.println("Sweep");
              }
          
              public void wash() {
                  System.out.println("Wash");
              }
          
              public void buyRice() {
                  System.out.println("Buy rice");
              }
          }
          
        • 创建做好事的类,学雷锋的大学生Undergraduate,及社区志愿者Volunteer
        • public class Undergraduate extends LeiFeng {
              
          }
          
          public class Volunteer extends LeiFeng {
              
          }
          
        • 创建雷锋工厂类IFactory,再定义学雷锋的大学生工厂UndergraduateFactory和社区志愿者工厂VolunteerFactory
        • public interface IFactory {
              public LeiFeng createLeiFeng();
          }
          
          public class UndergraduateFactory implements IFactory {
              @Override
              public LeiFeng createLeiFeng() {
                  return new Undergraduate();
              }
          }
          
          public class VolunteerFactory implements IFactory {
              @Override
              public LeiFeng createLeiFeng() {
                  return new Volunteer();
              }
          }
          
        • 调用方
        • public class FactoryMethodClient {
              public static void main(String[] args) {
                  IFactory factory = new UndergraduateFactory();
                  LeiFeng student = factory.createLeiFeng();
                  student.buyRice();
                  student.sweep();
                  student.wash();
          
                  LeiFeng volunteer = new VolunteerFactory().createLeiFeng();
                  volunteer.buyRice();
                  volunteer.sweep();
                  volunteer.wash();
                }
          }
          
      • 工厂方法模式通用结构示意图如下(引申)
        • 工厂方法模式UML
  • 2.5 建造者模式

    • 描述:建造者模式(Builder)复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的
    • 区别:与工厂模式相比,建造者模式更关注与零件装配的顺序
    • 原则1:高层次的类不应依赖低层次的类,都应依赖于抽象接口
    • 原则2:抽象不应该依赖细节,细节应该依赖抽象
    • 原则3:适合同类算法较多的场景,较少不太适合
    • 好处1:使得建造代码与表示代码分离,易扩展
    • 好处2:便于控制细节风险
    • 坏处1:产品必须有共同点,范围有限制
    • 坏处2:如内部变化复杂,会有很多的建造类
    • eg:(创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化;一些基础部件不变,而其组合经常变化)
      • 场景:构造小人的过程是稳定的,都需要头身手脚,具体建造的"细节"不同,有高矮胖瘦
      • 步骤:
        • 先定义一个抽象的建造人的类,把这个过程稳定住,里面有构建头身手脚的抽象方法;
        • 然后建造具体的小人,去继承上面的抽象类;
        • 创建一个指挥者,用它来控制构建过程,隔离用户与构造过程的关联
      • 代码实现:
        • PersonBuilder 抽象类
        • import java.awt.*;
          
          public abstract class PersonBuilder {
              protected Graphics2D g;
              protected Pen p;
          
              public PersonBuilder(Graphics2D g, Pen p) {
                  g.setStroke(new BasicStroke(p.getLineWidth()));
                  g.setColor(p.getColor());
                  this.g = g;
                  this.p = p;
              }
          
              public abstract void buildHead();
              public abstract void buildBody();
              public abstract void buildArmLeft();
              public abstract void buildArmRight();
              public abstract void buildLegLeft();
              public abstract void buildLegRight();
          }
          
        • PersonFatBuilder 具体类
        • import java.awt.*;
          
          public class PersonFatBuilder extends PersonBuilder {
              public PersonFatBuilder(Graphics2D g, Pen p) {
                  super(g, p);
              }
          
              @Override
              public void buildHead() {
                  g.drawOval(200, 70, 30, 30);
              }
          
              @Override
              public void buildBody() {
                  g.drawRect(185, 100, 60, 30);
              }
          
              @Override
              public void buildArmLeft() {
                  g.drawLine(205, 100, 175, 110);
              }
          
              @Override
              public void buildArmRight() {
                  g.drawLine(225, 100, 250, 110);
              }
          
              @Override
              public void buildLegLeft() {
                  g.drawLine(205, 130, 175, 150);
              }
          
              @Override
              public void buildLegRight() {
                  g.drawLine(225, 130, 250, 150);
              }
          }
          
        • PersonThinBuilder 具体类
        • import java.awt.*;
          
          public class PersonThinBuilder extends PersonBuilder {
              public PersonThinBuilder(Graphics2D g, Pen p) {
                  super(g, p);
              }
          
              @Override
              public void buildHead() {
                  g.drawOval(50, 20, 30, 30);
              }
          
              @Override
              public void buildBody() {
                  g.drawRect(60, 50, 10, 50);
              }
          
              @Override
              public void buildArmLeft() {
                  g.drawLine(60, 50, 40, 100);
              }
          
              @Override
              public void buildArmRight() {
                  g.drawLine(70, 50, 90, 100);
              }
          
              @Override
              public void buildLegLeft() {
                  g.drawLine(60, 100, 45, 150);
              }
          
              @Override
              public void buildLegRight() {
                  g.drawLine(70, 100, 85, 150);
              }
          }
          
        • PersonDirector
        • public class PersonDirector {
          
              private PersonBuilder pb;
          
              public PersonDirector(PersonBuilder pb) {
                  this.pb = pb;
              }
          
              public void createPerson() {
                  pb.buildHead();
                  pb.buildBody();
                  pb.buildArmLeft();
                  pb.buildArmRight();
                  pb.buildLegLeft();
                  pb.buildLegRight();
              }
          }
          
        • Pen
        • import java.awt.*;
          
          public class Pen {
              private int lineWidth;
              private Color color;
          
              public Pen(int lineWidth, Color color) {
                  this.lineWidth = lineWidth;
                  this.color = color;
              }
          
              public int getLineWidth(){
                  return lineWidth;
              }
          
              public Color getColor(){
                  return color;
              }
          }
          
        • BuilderMain 方法
        • import javax.swing.*;
          import java.awt.*;
          
          public class BuilderMain {
              public static void main(String[] args) {
                  JFrame jFrame = new JFrame();
          
                  JPanel jpanel = new JPanel() {
                      @Override
                      public void paint(Graphics graphics) {
                          super.paint(graphics);
                          PersonBuilder ptb = new PersonThinBuilder((Graphics2D) graphics, new Pen(2, Color.BLUE));
                          PersonDirector pd = new PersonDirector(ptb);
                          pd.createPerson();
                          PersonBuilder pfb = new PersonFatBuilder((Graphics2D) graphics, new Pen(3, Color.YELLOW));
                          pd = new PersonDirector(pfb);
                          pd.createPerson();
                      }
                  };
          
                  jFrame.add(jpanel);
                  jFrame.setSize(300, 300);
                  jFrame.setVisible(true);
                  jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              }
          }
          
      • 建造者模式通用结构示意图如下(引申)
        建造者模式UML
  • 2.6 观察者模式又叫发布-订阅模式

    • 描述:观察者模式又叫发布-订阅(Publish/Subscribe)模式,描述了单个对象和一个或多个对象之间的发布-订阅关系
    • 原则1:当一个对象的改变需要同时改变多个(不知道具体数目)对象时。
    • 原则2:当一个抽象模型的两个方面一方依赖于另一方时,将两者封装在独立的对象中
    • 好处1:Subject 和 Observer 之间松耦合,可以轻松扩展。而且两者都可以扩展,不会对系统造成影响。
    • 好处2:支持广播通信,不需要指定接收者,而且可以随时增删 Observer
    • 坏处1:不同的订阅者可能需要不同的更新(功能),而不是所有的都一样。比如炒股的可能要切换桌面,而看 NBA 的既要切换桌面还得关掉声音。
    • 坏处2:Subject 依赖于 Observer 对抽象接口的实现,没有实现就无法更新。比如炒股的没有实现更新方法,那他的摸鱼行为自然就要暴露了
    • eg:(推模型:Subject 起主导作用,向 Observer 推送。拉模型:Subject 对变化进行广播,由 Observer 负责拉取更新)
      • 场景:针对领导的群就是 Subject,员工则是 Observer,一个 Subject 可以有多个 Observer,它不需要关心到底有哪些 Observer,Observer 之间也不需要知道彼此存在。当 Subject 的状态发生变化(即领导回来)时,所有的 Observer 都会得到通知,并更新自己的行为(努力工作)。
      • 当然,反过来一个 Observer 可以订阅多个 Subject,任意一个 Subject 的状态发生变化,该 Observer 都会得到通知。这样就既解决了一致性问题,又不会过紧耦合。
      • 步骤:
        • 主题抽象类 Subject,定义 attachdetachinform 方法。
        • 观察者抽象类 Observer,定义 update 方法。
        • 具体主题类 Boss
        • 具体观察者类 NBAObserverStockObserver 等,每个类重写自己的 update 方法
      • 代码实现:
        • Subject
        • public interface Subject {
              void attach(Observer observer);
              void detach(Observer observer);
              void inform();
          
              String getSubjectState();
              void setSubjectState(String action);
          }
          
        • Observer
        • public abstract class Observer {
              protected String name;
              protected Subject sub;
          
              public Observer(String name, Subject sub) {
                  this.name = name;
                  this.sub = sub;
              }
          
              public abstract void update();
          }
          
        • ConcreteSubject
        • public class Boss implements Subject {
              private List<Observer> observers = new ArrayList<>();
              private String action;
          
              @Override
              public void attach(Observer observer) {
                  observers.add(observer);
              }
          
              @Override
              public void detach(Observer observer) {
                  observers.remove(observer);
              }
          
              @Override
              public void inform() {
                  for(Observer o : observers){
                      o.update();
                  }
              }
          
              @Override
              public String getSubjectState() {
                  return action;
              }
          
              @Override
              public void setSubjectState(String action) {
                  this.action = action;
              }
          }
          
        • ConcreteObserver
        • public class NBAObserver extends Observer {
              public NBAObserver(String name, Subject sub) {
                  super(name, sub);
              }
          
              @Override
              public void update() {
                  System.out.println(sub.getSubjectState() + " " + name + " 关闭NBA直播,继续工作!");
              }
          }
          
          public class StockObserver extends Observer {
              public StockObserver(String name, Subject sub) {
                  super(name, sub);
              }
          
              @Override
              public void update() {
                  System.out.println(sub.getSubjectState() + " " + name + " 关闭股票行情,继续工作!");
              }
          }
          
        • 调用方
        • public class Main {
              public static void main(String[] args) {
                  Boss huhansan = new Boss();
          
                  Observer tongshi1 = new StockObserver("魏关姹", huhansan);
                  Observer tongshi2 = new NBAObserver("易管查", huhansan);
          
                  huhansan.attach(tongshi1);
                  huhansan.attach(tongshi2);
          
                  huhansan.detach(tongshi1);
                  huhansan.setSubjectState("我胡汉三回来了!");
                  huhansan.inform();
              }
          }
          
      • 观察者模式通用结构示意图如下(引申)
  • 参考资料:《深入设计模式》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值