设计模式系列 - 行为型模式(下)

行为设计模式是识别对象之间的通信模式,行为模式涉及对象之间的责任分配,或者,将行为封装在对象中并将请求委托给它,也就是对象之间的关系。

涉及:
* 状态模式
中介模式
* 观察者模式
备忘录模式
迭代器模式
命令模式
* 策略模式
* 模板模式
* 访客模式示例
责任链模式

观察者模式

根据GoF定义,observer模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,它的所有依赖关系都会被自动通知和更新。它也被称为发布-订阅模式。
在观察者模式中,有许多观察者(订阅者对象)正在观察特定的主题(发布者对象)。观察者向一个主题注册,以便在该主题内部发生更改时获得通知。
观察者对象可以在任何时间点注册或从主体注销。它有助于使对象对象松散耦合。
关键代码:在抽象类里有一个 ArrayList 存放观察者们

Subject.java
public interface Subject
{
    public void attach(Observer o);
    public void detach(Observer o);
    public void notifyUpdate(Message m);
}

MessagePublisher.java
import java.util.ArrayList;
import java.util.List;

public class MessagePublisher implements Subject {

    private List<Observer> observers = new ArrayList<>();

    @Override
    public void attach(Observer o) {
        observers.add(o);
    }

    @Override
    public void detach(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyUpdate(Message m) {
        for(Observer o: observers) {
            o.update(m);
        }
    }
}
//Observer and ConcreteObservers
Observer.java
public interface Observer
{
    public void update(Message m);
}
MessageSubscriberOne.java
public class MessageSubscriberOne implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberOne :: " + m.getMessageContent());
    }
}
MessageSubscriberTwo.java
public class MessageSubscriberTwo implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberTwo :: " + m.getMessageContent());
    }
}
MessageSubscriberThree.java
public class MessageSubscriberThree implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberThree :: " + m.getMessageContent());
    }
}
//State object
//This must be an immutable object so that no class can modify it’s content by mistake.

Message.java
public class Message
{
    final String messageContent;

    public Message (String m) {
        this.messageContent = m;
    }

    public String getMessageContent() {
        return messageContent;
    }
}
//Now test the communication between publisher and subscribers.
Main.java
public class Main
{
    public static void main(String[] args)
    {
        MessageSubscriberOne s1 = new MessageSubscriberOne();
        MessageSubscriberTwo s2 = new MessageSubscriberTwo();
        MessageSubscriberThree s3 = new MessageSubscriberThree();

        MessagePublisher p = new MessagePublisher();

        p.attach(s1);
        p.attach(s2);

        p.notifyUpdate(new Message("First Message"));   //s1 and s2 will receive the update

        p.detach(s1);
        p.attach(s3);

        p.notifyUpdate(new Message("Second Message")); //s2 and s3 will receive the update
    }
}
Program output:
MessageSubscriberOne :: First Message
MessageSubscriberTwo :: First Message
MessageSubscriberTwo :: Second Message
MessageSubscriberThree :: Second Message

状态模式

根据GoF的定义,状态允许对象在其内部状态改变时改变其行为。对象的每个可能状态都应有一个单独的具体类。每个具体的状态对象都有接受或拒绝状态转换请求的逻辑,该请求基于其当前状态和作为方法参数传递给它的上下文信息。
当我们处理的对象在其生命周期中处于不同的状态,以及它如何基于其当前状态处理传入请求(或进行状态转换)时,我们都可以使用状态模式。
如果我们在这种情况下不使用状态模式,我们最终会得到很多If-else语句,这些语句会使代码基变得难看、不必要的复杂和难以维护。

PackageState.java
public interface PackageState
{
    public void updateState(DeliveryContext ctx);
}
Acknowledged.java
public class Acknowledged implements PackageState
{
    //Singleton
    private static Acknowledged instance = new Acknowledged();

    private Acknowledged() {}

    public static Acknowledged instance() {
        return instance;
    }

    //Business logic and state transition
    @Override
    public void updateState(DeliveryContext ctx)
    {
        System.out.println("Package is acknowledged !!");
        ctx.setCurrentState(Shipped.instance());
    }
}
Shipped.java
public class Shipped implements PackageState
{
    //Singleton
    private static Shipped instance = new Shipped();

    private Shipped() {}

    public static Shipped instance() {
        return instance;
    }

    //Business logic and state transition
    @Override
    public void updateState(DeliveryContext ctx)
    {
        System.out.println("Package is shipped !!");
        ctx.setCurrentState(InTransition.instance());
    }
}
InTransition.java
public class InTransition implements PackageState
{
    //Singleton
    private static InTransition instance = new InTransition();

    private InTransition() {}

    public static InTransition instance() {
        return instance;
    }

    //Business logic and state transition
    @Override
    public void updateState(DeliveryContext ctx)
    {
        System.out.println("Package is in transition !!");
        ctx.setCurrentState(OutForDelivery.instance());
    }
}
OutForDelivery.java
public class OutForDelivery implements PackageState
{
    //Singleton
    private static OutForDelivery instance = new OutForDelivery();

    private OutForDelivery() {}

    public static OutForDelivery instance() {
        return instance;
    }

    //Business logic and state transition
    @Override
    public void updateState(DeliveryContext ctx)
    {
        System.out.println("Package is out of delivery !!");
        ctx.setCurrentState(Delivered.instance());
    }
}
Delivered.java
public class Delivered implements PackageState
{
    //Singleton
    private static Deliveredinstance = new Delivered();

    private Delivered() {}

    public static Deliveredinstance() {
        return instance;
    }

    //Business logic
    @Override
    public void updateState(DeliveryContext ctx)
    {
        System.out.println("Package is delivered!!");
    }
}

DeliveryContext.java
public class DeliveryContext {

    private PackageState currentState;
    private String packageId;

    public DeliveryContext(PackageState currentState, String packageId)
    {
        super();
        this.currentState = currentState;
        this.packageId = packageId;

        if(currentState == null) {
            this.currentState = Acknowledged.instance();
        }
    }

    public PackageState getCurrentState() {
        return currentState;
    }

    public void setCurrentState(PackageState currentState) {
        this.currentState = currentState;
    }

    public String getPackageId() {
        return packageId;
    }

    public void setPackageId(String packageId) {
        this.packageId = packageId;
    }

    public void update() {
        currentState.updateState(this);
    }
}
Now test the code.

Main.java
public class Main
{
    public static void main(String[] args)
    {
        DeliveryContext ctx = new DeliveryContext(null, "Test123");

        ctx.update();
        ctx.update();
        ctx.update();
        ctx.update();
        ctx.update();
    }
}
Program Output:

Package is acknowledged !!
Package is shipped !!
Package is in transition !!
Package is out of delivery !!
Package is delivered !!

策略模式

我们在运行时从多个其他实现中为同一任务选择算法或任务的特定实现。重要的一点是,这些实现是可互换的——基于任务,可以在不干扰应用程序工作流的情况下选择实现。
策略模式包括从其宿主类中移除算法并将其放在单独的类中,以便在相同的编程上下文中可能有不同的算法(即策略),这些算法可以在运行时选择。
策略模式允许客户机代码从一系列相关但不同的算法中进行选择,并提供了一种在运行时根据客户机上下文选择任何算法的简单方法。

关键点:典型的面向接口编程。

ISocialMediaStrategy.java

public interface ISocialMediaStrategy
{
    public void connectTo(String friendName);
}
SocialMediaContext.java

public class SocialMediaContext
{
    ISocialMediaStrategy smStrategy;

    public void setSocialmediaStrategy(ISocialMediaStrategy smStrategy)
    {
        this.smStrategy = smStrategy;
    }

    public void connect(String name)
    {
        smStrategy.connectTo(name);
    }
}
FacebookStrategy.java
public class FacebookStrategy implements ISocialMediaStrategy {

    public void connectTo(String friendName)
    {
        System.out.println("Connecting with " + friendName + " through Facebook");
    }
}
GooglePlusStrategy.java

public class GooglePlusStrategy implements ISocialMediaStrategy {

    public void connectTo(String friendName)
    {
        System.out.println("Connecting with " + friendName + " through GooglePlus");
    }
}
TwitterStrategy.java
public class TwitterStrategy implements ISocialMediaStrategy {

    public void connectTo(String friendName)
    {
        System.out.println("Connecting with " + friendName + " through Twitter");
    }
}
OrkutStrategy.java
public class OrkutStrategy implements ISocialMediaStrategy {

    public void connectTo(String friendName)
    {
        System.out.println("Connecting with " + friendName + " through Orkut [not possible though :)]");
    }
}

//Demo
//Now see how these strategies can be used in runtime.
public class Demo {
    public static void main(String[] args) {

        // Creating social Media Connect Object for connecting with friend by
        // any social media strategy.
        SocialMediaContext context = new SocialMediaContext();

        // Setting Facebook strategy.
        context.setSocialmediaStrategy(new FacebookStrategy());
        context.connect("Lokesh");

        System.out.println("====================");

        // Setting Twitter strategy.
        context.setSocialmediaStrategy(new TwitterStrategy());
        context.connect("Lokesh");

        System.out.println("====================");

        // Setting GooglePlus strategy.
        context.setSocialmediaStrategy(new GooglePlusStrategy());
        context.connect("Lokesh");

        System.out.println("====================");

        // Setting Orkut strategy.
        context.setSocialmediaStrategy(new OrkutStrategy());
        context.connect("Lokesh");
    }
}
Output:

Connecting with Lokesh through Facebook
====================
Connecting with Lokesh through Twitter
====================
Connecting with Lokesh through GooglePlus
====================
Connecting with Lokesh through Orkut [not possible though :)]

模板模式

模板方法设计模式是一种被广泛接受的行为设计模式,用于在编程环境中实施某种算法(固定步骤集)。它定义了执行一个多步骤算法的顺序步骤,还可以提供一个默认实现.
模板法模式的适用性:
当我们有预定义的步骤来实现一些算法时。
当我们想要避免重复代码时,移动基类中的公共实现和步骤。

假设我们需要建造有特定步骤的房子。有些步骤有默认实现,有些步骤没有默认实现。
统一施工的默认实现步骤:

  • 地基施工
  • 屋顶施工

个性化施工的实现的步骤(比如针对混凝土墙、玻璃墙、砖墙等)

  • 墙体施工
  • 门窗施工
  • 绘画
  • 室内装饰

关键代码:部分步骤在抽象类实现,其他步骤在子类实现。

House.java
public abstract class House {
    /**
     * This is the template method we are discussing. This method should be
     * final so that other class can‘t re-implement and change the order of the
     * steps.
     */
    public final void buildhouse() {
        constructBase();
        constructRoof();
        constructWalls();
        constructWindows();
        constructDoors();
        paintHouse();
        decorateHouse();
    }

    public abstract void decorateHouse();

    public abstract void paintHouse();

    public abstract void constructDoors();

    public abstract void constructWindows();

    public abstract void constructWalls();

    /**
     * final implementation of constructing roof - final as all type of house
     * Should build roof in same manner.
     */
    private final void constructRoof() {
        System.out.println("Roof has been constructed.");
    }

    /**
     * final implementation of constructing base - final as all type of house
     * Should build base/foundation in same manner.
     */
    private final void constructBase() {
        System.out.println("Base has been constructed.");
    }
}
ConcreteWallHouse.java
public class ConcreteWallHouse extends House {
      @Override
      public void decorateHouse() {
            System.out.println(“Decorating Concrete Wall House”);
      }
      @Override
      public void paintHouse() {
            System.out.println(“Painting Concrete Wall House”);
      }
      @Override
      public void constructDoors() {
            System.out.println(“Constructing Doors for Concrete Wall House”);
      }
      @Override
      public void constructWindows() {
            System.out.println(“Constructing Windows for Concrete Wall House”);
      }
      @Override
      public void constructWalls() {
            System.out.println(“Constructing Concrete Wall for my House”);
      }
}
GlassWallHouse.java
public class GlassWallHouse extends House {
    @Override
    public void decorateHouse() {
        System.out.println("Decorating Glass Wall House");
    }

    @Override
    public void paintHouse() {
        System.out.println("Painting Glass Wall House");
    }

    @Override
    public void constructDoors() {
        System.out.println("Constructing Doors for Glass Wall House");
    }

    @Override
    public void constructWindows() {
        System.out.println("Constructing Windows for Glass Wall House");
    }

    @Override
    public void constructWalls() {
        System.out.println("Constructing Glass Wall for my House");
    }
}
Demo
public class Demo {
      public static void main(String[] args) {

            System.out.println(“Going to build Concrete Wall House”);

            House house = new ConcreteWallHouse();
            house.buildhouse();

            System.out.println(“Concrete Wall House constructed successfully”);

            System.out.println(“********************”);

            System.out.println(“Going to build Glass Wall House”);

            house = new GlassWallHouse();
            house.buildhouse();

            System.out.println(“Glass Wall House constructed successfully”);
      }
}
Output:

Going to build Concrete Wall House
Base has been constructed.
Roof has been constructed.
Constructing Concrete Wall for my House
Constructing Windows for Concrete Wall House
Constructing Doors for Concrete Wall House
Painting Concrete Wall House
Decorating Concrete Wall House
Concrete Wall House constructed successfully

********************

Going to build Glass Wall House
Base has been constructed.
Roof has been constructed.
Constructing Glass Wall for my House
Constructing Windows for Glass Wall House
Constructing Doors for Glass Wall House
Painting Glass Wall House
Decorating Glass Wall House
Glass Wall House constructed successfully

访问者模式

访问者设计模式是一种将算法与其操作的对象结构分离的方法。这种分离的一个实际结果是能够在不修改现有对象结构的情况下向现有对象结构添加新操作。这是遵循开放/封闭原则(实体设计原则之一)的一种方法。
上述设计灵活性允许向任何对象层次结构添加方法,而无需修改为层次结构编写的代码。更确切地说,使用双调度机制来实现此功能。Double dispatch是一种特殊的机制,它根据调用中涉及的两个对象的运行时类型,将函数调用分派给不同的具体函数。

关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

Router.java
public interface Router
{
    public void sendData(char[] data);
    public void acceptData(char[] data);

    public void accept(RouterVisitor v);
}
DLinkRouter.java
public class DLinkRouter implements Router{

    @Override
    public void sendData(char[] data) {
    }

    @Override
    public void acceptData(char[] data) {
    }

    @Override
    public void accept(RouterVisitor v) {
        v.visit(this);
    }
}
LinkSysRouter.java
public class LinkSysRouter implements Router{

    @Override
    public void sendData(char[] data) {
    }

    @Override
    public void acceptData(char[] data) {
    }

    @Override
    public void accept(RouterVisitor v) {
        v.visit(this);
    }
}
TPLinkRouter.java
public class TPLinkRouter implements Router{

    @Override
    public void sendData(char[] data) {
    }

    @Override
    public void acceptData(char[] data) {
    }

    @Override
    public void accept(RouterVisitor v) {
        v.visit(this);
    }
}
RouterVisitor.java
public interface RouterVisitor {
    public void visit(DLinkRouter router);
    public void visit(TPLinkRouter router);
    public void visit(LinkSysRouter router);
}
LinuxConfigurator.java
public class LinuxConfigurator implements RouterVisitor{

    @Override
    public void visit(DLinkRouter router) {
        System.out.println("DLinkRouter Configuration for Linux complete !!");
    }

    @Override
    public void visit(TPLinkRouter router) {
        System.out.println("TPLinkRouter Configuration for Linux complete !!");
    }

    @Override
    public void visit(LinkSysRouter router) {
        System.out.println("LinkSysRouter Configuration for Linux complete !!");
    }
}
MacConfigurator.java
public class MacConfigurator implements RouterVisitor{

    @Override
    public void visit(DLinkRouter router) {
        System.out.println("DLinkRouter Configuration for Mac complete !!");
    }

    @Override
    public void visit(TPLinkRouter router) {
        System.out.println("TPLinkRouter Configuration for Mac complete !!");
    }

    @Override
    public void visit(LinkSysRouter router) {
        System.out.println("LinkSysRouter Configuration for Mac complete !!");
    }
}

TestVisitorPattern.java
public class TestVisitorPattern extends TestCase
{
    private MacConfigurator macConfigurator;
    private LinuxConfigurator linuxConfigurator;
    private DLinkRouter dlink;
    private TPLinkRouter tplink;
    private LinkSysRouter linksys;

    public void setUp()
    {
        macConfigurator = new MacConfigurator();
        linuxConfigurator = new LinuxConfigurator();

        dlink = new DLinkRouter();
        tplink = new TPLinkRouter();
        linksys = new LinkSysRouter();
    }

    public void testDlink()
    {
        dlink.accept(macConfigurator);
        dlink.accept(linuxConfigurator);
    }

    public void testTPLink()
    {
        tplink.accept(macConfigurator);
        tplink.accept(linuxConfigurator);
    }

    public void testLinkSys()
    {
        linksys.accept(macConfigurator);
        linksys.accept(linuxConfigurator);
    }
}

Output:

DLinkRouter Configuration for Mac complete !!
DLinkRouter Configuration for Linux complete !!
LinkSysRouter Configuration for Mac complete !!
LinkSysRouter Configuration for Linux complete !!
TPLinkRouter Configuration for Mac complete !!
TPLinkRouter Configuration for Linux complete !!

原文地址:https://www.cnblogs.com/starcrm/p/12584322.html

时间: 2024-10-22 19:59:54

设计模式系列 - 行为型模式(下)的相关文章

设计模式系列 - 创建型模式

单例模式 懒汉式,线程不安全. 除非是单线程程序,否则不推荐使用. public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 饿汉式,线程安全 当程序总是使用这个

设计模式之创建型模式(上)

没有总结的学习不算学习,这一个月的学习可谓收获多多啊,接下来与大家分享一下. 一.设计模式的分类 总体来说设计模式分为三大类: 1.创建型模式,共五种. 2.结构型模式,共七种. 3.行为型模式,共十一种. 首先研究创建型模式 二. 概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独 立于如何创建.组合和表示它的那些对象. 三. 为什么需要创建型模式 所有的创建型模式都有两个永恒的主旋律: 第一,它们都将系统使用哪些具体类的信息封装起来: 第二,它们隐藏了这些类的实例

Java经典23种设计模式之行为型模式(三)

本文接着介绍11种行为型模式里的备忘录模式.观察者模式.状态模式. 一.备忘录模式 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态.还是比较好理解的. 1.Memento 备忘录存储原发器对象的内部状态,这个类就是要存储的对象的状态.状态需要多少个变量,在Memento里就写多少个变量. public class Memento { private String state; public Meme*to(String st

Java经典23种设计模式之行为型模式(一)

行为型设计模式有11种,分别是Chain of Responsibility ( 责任链模式 ).Command ( 命令模式 ).Interpreter ( 解释器模式 ) .Iterator ( 迭代器模式 ).Mediator ( 中介者模式 ) .Memento ( 备忘录模式 ) .Observer ( 观察者模式 ).State ( 状态模式 ) .Strategy ( 策略模式 ).TemplateMethod ( 模板方法 ).Visitor ( 访问者模式 ),本文介绍这11种

设计模式 (创建型模式)

  设计模式 创建型模式 1.创建型模式         创建型模式,包括了5种设计模式,分别是 Singleton (单例模式),Factory(工厂模式),AbstractFactory(抽象工厂模式),Builder(创建者),Prototype(原型) ,创建型模式主要作用就是抽象了实例化过程.他们帮助一个系统独立于如何创建.组合和表示他的那些对象.一个类创建型模式使用继承改变被实例化的类.而一个对象创建型模式将实例化委托给另一个对象. 2.Singleton (单例模式)      单

设计模式(33)-----行为型模式-----访问者设计模式

访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变.这种类型的设计模式属于行为型模式.根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作. 介绍 意图:主要将数据结构与数据操作分离. 主要解决:稳定的数据结构和易变的操作耦合问题. 何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封

设计模式系列之工厂模式

设计模式一直是面向对象软件设计中最重要的一个领域,围绕设计模式讨论的话题也是数不胜数,其中GOF代表的23种设计模式更是经典之著.这个系列中我将会从自己的理解出发,阐述每种设计模式的思想,作用和利弊. 一. 设计模式概念 要讲解设计模式,必然先要说清楚两个问题, 1.什么是设计模式? 2.为什么需要设计模式? 对于设计模式,GOF是这么定义的:设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述,更特殊地,将之放到面向对象软件设计中来讲,设计模式可以被认为是实践中总结出的设计

设计模式之创建型模式

一.前言 设计模式应该是在软件工程的背景下进行讨论的,而不是为了设计模式而论设计模式.设计模式是软件工程面向对象设计工作中一个抽象.归纳.总结的过程.软件设计的最高目标和最高准则就是易扩展,易复用,易维护, 灵活性高,高可用,稳定性高一切的设计原则和设计模式最终的目标都是向这个目标靠拢的. 二.面向对象设计六大原则 任何的设计模式都是基于面向对象的特性(抽象.封装.继承.多态)和设计原则进行设计和实现的,是面向对象设计原则的在不同场景下的实现方案. 抽象:抽离变化的部分,引入抽象层,实现具体实现

Android设计模式系列--工厂方法模式

工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式.android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类.今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式. 工厂方法模式,Factory Method,简单的方式,不简单的应用. 1.意图定义一个用于创建对象的接口,让子类决定实例化哪个类.工厂方式模式使一个类的实例化延迟到其子类.热门词汇:虚构造器 延迟 创建对象 子类 2