行为设计模式是识别对象之间的通信模式,行为模式涉及对象之间的责任分配,或者,将行为封装在对象中并将请求委托给它,也就是对象之间的关系。
涉及:
* 状态模式
中介模式
* 观察者模式
备忘录模式
迭代器模式
命令模式
* 策略模式
* 模板模式
* 访客模式示例
责任链模式
观察者模式
根据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 !!