• 设计模式系列


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

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

    观察者模式

    根据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 !!
  • 相关阅读:
    LA 3135 优先队列
    uva 11991 查询中容器的运用
    uva 11995 判别数据类型
    LA 4973异面线段
    LA 2797 平面区域dfs
    LA 2218 半平面交
    poj 3525 求凸包的最大内切圆
    poj 1031 多边形对点(向周围发射光线)的覆盖
    poj 1269 直线间的关系
    kotlin学习笔记-异常好玩的list集合总结
  • 原文地址:https://www.cnblogs.com/starcrm/p/12584322.html
Copyright © 2020-2023  润新知