这里结合多种模式完成需求,为了体现各模式的使用价值,在对比中对某种模式的特点有一个相对形象的认识。还是一坦克大战作为需求原型,因为需求简单,易于理解,不会在需求本身上消耗太多精力,更容易专注模式本身。
需求:坦克大战
创建两种坦克
坦克类型 | 射程 | 速度 |
b70 | 70米 | 时/70公里 |
b50 | 50米 | 时/50公里 |
类图
需求设计思路
坦克,不同的型号采用策略模式,这里用不同的规格承载策略,其实就是70和50两个参数
在调用的过程中,采用的是装饰模式,对象的套用关系是 坦克(射击(跑(客户端)));调用流程就是 坦克->create(射击->create(跑->update(客户端->ceateTankFinish)));这就是一个装饰模式的调用过程。其实这个结构也可以说是职责链,只不过这个函数执行的功能都在基础功能上有叠加功能,并不是将职责下抛。所以叫装饰模式更像一些,但其实完全满足职责链的结构关系,这里也能看出职责链和装饰模式的对象结果关系机会相同,都是有一个桥接链构成。
基础功能的承载就是“射击”和“跑”两个功能,结合不同的参数体现射程和跑的速度。这里“射击”和“跑”两个对象用的享元模式。
功能对象是用命令模式,功能是以命令对象的方式加载给坦克的,这就是整个坦克的函数执行链的基础。用命令模式把函数储存成对象链,这也是命令模式在这里的运用。
坦克的两种型号的抽象用策略模式,抽象的差别用两个规格承载,70,50;功能是固定的一个“射击”,一个“跑”,这两个功能是静态的,只是注入的规格不同,体现不同的功能,所以用享元模式。功能的组装过程是 坦克装“射击 ”,“射击”装“跑”,跑装“客户端”;这里的这个组装过程用的装饰模式;这里的“射击”和“跑”用的命令模式,所以组装的对象就等同于组装函数;坦克->射击->跑->客户端,这一系列的过程是否像一个职责链,这里你也可以体会一下装饰模式和职责链的共性和个性差别。坦克一创建就通知,射击,射击一运行就通知跑,跑一运行就通知客户端,坦克->射击->跑->客户端,这一通知的链条是否像是观察者模式,被观察的对象有动作,我就会收到通知,虽然标准的观察者模式,都是一对多的,但是多少并不是核心的,重要的是对象的联动关系,当然 联动的关键是状态,这里的状态就是我动你就动,隐形的状态传递多久是动与不动,只不过没有提出一个专门的状态。
代码
import java.util.HashMap;
//--接口层---------------------------------------------------
//基本功能基类
class Function{
public String mStr;
public String mUnit;
Function(String str,String unit){
mStr = str;
mUnit = unit;
}
public void exe(int specification) {
System.out.println(mStr+specification+mUnit);
}
};
// Strategy Pattern
// 功能执行接口
interface IFun{
void exe();
}
//命令模式-用于创建坦克
interface IHandler{
void create(Tank t);
}
//抽象坦克接口定义
interface IStrategy{
//algorithm
void create();
void update(Tank t);
}
//功能规格控制接口
interface ISpecificationOfTank{
int getSpecification();
}
// 功能接口抽象-和功能规格控制接口 绑定
abstract class ConcreteFun implements IFun{
public ConcreteFun(ISpecificationOfTank s) {
mSpecificationOfTank = s;
}
protected ISpecificationOfTank mSpecificationOfTank;
}
//Concrete
//--实现层-----------------------------------------------------------
//规格获取类实现
class ConcreteSpecification implements ISpecificationOfTank{
int mSpecification;
public ConcreteSpecification(int value) {
mSpecification = value;
}
public int getSpecification() {
return mSpecification;
}
}
//基本功能实现-设计
class ShotFlyweight extends Function{
public ShotFlyweight() {
super("发射距离","米");
}
}
//基本功能实现-跑
class RunFlyweight extends Function{
public RunFlyweight() {
super("速度","公里");
}
}
//享元模式-管理功能类,使功能对象享元
class FlyweightFactory{
static FlyweightFactory mFlyweightFactory = new FlyweightFactory();
static FlyweightFactory get() {
return mFlyweightFactory;
}
HashMap mMaps = new HashMap();
public Function GetFlyweitht(String key) {
Function f = mMaps.get(key);
if(f == null) {
return createFlyweight(key);
}else
{
return f;
}
}
public Function createFlyweight(String key) {
Function f = null;
if(key == "shot") {
f = new ShotFlyweight();
}else {
f = new RunFlyweight();
}
mMaps.put(key, f);
return f;
}
}
//功能执行类实现-射击
class Shot extends ConcreteFun{
public Shot(ISpecificationOfTank s) {
super(s);
}
public void exe() {
//享元模式
//为了保证无论创建多少个坦克,射击和跑这两个功能共享
//这里采取了享元的设计模式
Function f = FlyweightFactory.get().GetFlyweitht("shot");
f.exe(mSpecificationOfTank.getSpecification());
}
}
//功能执行类实现-跑
class Run extends ConcreteFun{
public Run(ISpecificationOfTank s) {
super(s);
}
public void exe() {
//享元模式
Function f = FlyweightFactory.get().GetFlyweitht("run");
f.exe(mSpecificationOfTank.getSpecification());
}
}
//坦克定义
class Tank{
Shot mShot;
Run mRun;
public void exe() {
mShot.exe();
mRun.exe();
}
}
//功能抽象类-命令模式
abstract class Handler implements IHandler{
protected ISpecificationOfTank mSpecificationOfTank;
public Handler(ISpecificationOfTank s) {
mSpecificationOfTank = s;
}
}
//跑功能-命令模式
class HandlerRun extends Handler{
IStrategy mStrategy;
public HandlerRun(IStrategy stragegy,ISpecificationOfTank s) {
super(s);
mStrategy = stragegy;
}
public void create(Tank t) {
t.mRun = new Run(mSpecificationOfTank);
//跑掉坦克的update
//这里也是装饰模式的体现:
//嵌套结构: 设计对象(跑对象->create(坦克对象->update(客户端->ceateTankFinish)))
mStrategy.update(t);
}
}
//射击-命令模式
class HandlerSort extends Handler{
HandlerRun mNextHandler;
public HandlerSort(HandlerRun h,ISpecificationOfTank s){
super(s);
mNextHandler = h;
}
public void create(Tank t) {
t.mShot = new Shot(mSpecificationOfTank);
//这里就是套娃内部对想的调用 设计调运行
//装饰模式的体现
mNextHandler.create(t);
}
}
//抽象坦克-策略模式
class Strategy implements IStrategy{
HandlerSort mStartChain;
ISpecificationOfTank mSpecificationOfTank;
Client mClient;
public Strategy(Client c) {
mClient = c;
}
protected void myinit() {
//这里用了模版模式,套娃的方式,HandlerRun套this,HandlerSort套HandlerRun(endChain)
//所以当运行HandlerSort时也会运行跑,设计需要跑的配合
HandlerRun endChain = new HandlerRun(this,mSpecificationOfTank);
mStartChain = new HandlerSort(endChain,mSpecificationOfTank);
}
//当创建坦克后会调用这个函数,
//这里会调用mStartChain的create
//mStartChain的create调用时,会调用他桥接对象的create
//这个调用也是桥接和装饰模式结合的结构
public void create() {
Tank t = new Tank();
mStartChain.create(t);
}
//这里是观察着模式,坦克给客户端法通知
public void update(Tank t) {
mClient.ceateTankFinish(t);
}
}
//坦克70
class B70Strategy extends Strategy{
public B70Strategy(Client c) {
super(c);
//这里采用70 和 50 规格的不同策略 使用的是策略模式
mSpecificationOfTank = new ConcreteSpecification(70);
myinit();
}
}
//坦克50
class B50Strategy extends Strategy{
public B50Strategy(Client c) {
super(c);
//这里采用70 和 50 规格的不同策略 使用的是策略模式
mSpecificationOfTank = new ConcreteSpecification(50);
myinit();
}
}
//--用户调用层-------------------------------------------------
public class Client {
public static void main(String[] args) {
System.out.println("hello world !");
Client c = new Client();
IStrategy strategy = new B70Strategy(c);
strategy.create();
}
public void ceateTankFinish(Tank t) {
System.out.println("ceateTankFinish");
t.exe();
}
}
运行结果
桥接模式(Bridge Pattern)是一种结构型设计模式,旨在将抽象部分与它的实现部分分离,使它们可以独立地变化。桥接模式通过组合的方式,将两个独立变化的维度解耦,从而提高了系统的灵活性和可扩展性。
桥接模式的定义是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。该模式涉及一个接口,它充当一个“桥”,使得具体类可以在不影响客户端代码的情况下改变。
桥接模式的核心思想是将系统的抽象层次和实现层次分离,抽象层次定义了抽象接口,包含了一些抽象方法;实现层次则实现了这些抽象方法,并提供了具体的方法实现。通过组合的方式,将抽象层次和实现层次的对象关联起来,从而在运行时动态地组合不同的实现。
桥接模式包含以下角色:
桥接模式通常适用于以下场景:
以视频播放器的设计为例,可以使用桥接模式来处理视频格式和操作系统两个独立变化的维度。
定义实现化角色接口:
interface VideoPlayerImplementor {
void playVideo();
}
创建具体实现类:
class FLVVideoPlayer implements VideoPlayerImplementor {
public void playVideo() {
System.out.println("播放FLV格式的视频。");
}
}
class MP4VideoPlayer implements VideoPlayerImplementor {
public void playVideo() {
System.out.println("播放MP4格式的视频。");
}
}
定义抽象化角色:
abstract class VideoPlayer {
protected VideoPlayerImplementor implementor;
public VideoPlayer(VideoPlayerImplementor implementor) {
this.implementor = implementor;
}
public abstract void play();
}
创建修正抽象化角色:
class WindowsVideoPlayer extends VideoPlayer {
public WindowsVideoPlayer(VideoPlayerImplementor implementor) {
super(implementor);
}
public void play() {
System.out.println("在Windows系统上播放视频:");
implementor.playVideo();
}
}
class LinuxVideoPlayer extends VideoPlayer {
public LinuxVideoPlayer(VideoPlayerImplementor implementor) {
super(implementor);
}
public void play() {
System.out.println("在Linux系统上播放视频:");
implementor.playVideo();
}
}
客户端代码:
public class Client {
public static void main(String[] args) {
VideoPlayerImplementor flvPlayer = new FLVVideoPlayer();
VideoPlayerImplementor mp4Player = new MP4VideoPlayer();
VideoPlayer windowsFLVPlayer = new WindowsVideoPlayer(flvPlayer);
VideoPlayer linuxMP4Player = new LinuxVideoPlayer(mp4Player);
windowsFLVPlayer.play(); // 在Windows系统上播放FLV视频
linuxMP4Player.play(); // 在Linux系统上播放MP4视频
}
}
桥接模式是一种非常有用的设计模式,它通过将抽象部分与实现部分分离,使得系统可以独立地扩展这两个部分,从而提高了系统的灵活性和可扩展性。在实际应用中,桥接模式可以处理多个独立变化的维度,减少继承的使用,降低类之间的耦合度,使得系统更易于维护和扩展。
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式的核心思想是将算法的定义与使用分离,客户端代码不直接调用具体的算法,而是通过一个统一的接口(策略接口)来访问不同的算法。
策略模式通常包含以下几个角色:
if-else
或switch-case
语句,使代码更加清晰和简洁。策略模式适用于以下场景:
if-else
或switch-case
语句,用于根据不同的条件执行不同的算法,那么可以考虑使用策略模式来重构代码。以下是一个简单的策略模式示例,用于模拟不同支付方式的实现:
// 策略接口
interface PaymentStrategy {
void pay(double amount);
}
// 具体策略类:信用卡支付
class CreditCardStrategy implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
// 具体策略类:支付宝支付
class AlipayStrategy implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paid " + amount + " using Alipay.");
}
}
// 具体策略类:微信支付
class WeChatPayStrategy implements PaymentStrategy {
public void pay(double amount) {
System.out.println("Paid " + amount + " using WeChat Pay.");
}
}
// 上下文类
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay(double amount) {
if (paymentStrategy != null) {
paymentStrategy.pay(amount);
} else {
System.out.println("No payment strategy set.");
}
}
}
// 客户端代码
public class StrategyPatternExample {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 设置支付方式为信用卡支付
cart.setPaymentStrategy(new CreditCardStrategy());
cart.pay(100.0);
// 设置支付方式为支付宝支付
cart.setPaymentStrategy(new AlipayStrategy());
cart.pay(200.0);
// 设置支付方式为微信支付
cart.setPaymentStrategy(new WeChatPayStrategy());
cart.pay(300.0);
}
}
在这个示例中,PaymentStrategy
接口定义了支付的公共接口pay()
,CreditCardStrategy
、AlipayStrategy
和WeChatPayStrategy
是具体策略类,实现了不同的支付方式。ShoppingCart
是上下文类,维护了一个PaymentStrategy
类型的引用,可以在运行时设置不同的支付策略。客户端代码通过调用ShoppingCart
的pay()
方法,并使用不同的支付策略来进行支付操作。
策略模式是一种强大的设计模式,它通过将算法的定义与使用分离,提高了系统的灵活性和可扩展性。在实际应用中,策略模式可以应用于多种场景,如算法的动态选择、避免多重条件判断以及算法的封装等。通过合理地使用策略模式,可以使代码更加清晰、简洁和易于维护。
职责链模式(Chain of Responsibility Pattern),又称责任链模式,是一种行为型设计模式。它通过将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求为止,从而避免了请求的发送者和接收者之间的耦合关系。以下是关于职责链模式的详细解释:
职责链模式定义了一个请求处理的框架,请求沿着处理者链进行传递,每个处理者都有机会处理该请求,如果某个处理者不能处理该请求,则将该请求传递给链中的下一个处理者。
职责链模式通常包含以下角色:
优点:
缺点:
职责链模式适用于以下场景:
以下是一个简单的职责链模式示例,假设有一个日志系统,需要根据不同的日志级别(如INFO、DEBUG、ERROR)将日志消息传递给不同的处理器:
// 抽象处理者
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handle(String logMessage);
}
// 具体处理者:INFO日志处理器
class InfoHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("INFO")) {
System.out.println("INFO Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 具体处理者:DEBUG日志处理器
class DebugHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("DEBUG")) {
System.out.println("DEBUG Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 具体处理者:ERROR日志处理器
class ErrorHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("ERROR")) {
System.out.println("ERROR Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Handler infoHandler = new InfoHandler();
Handler debugHandler = new DebugHandler();
Handler errorHandler = new ErrorHandler();
infoHandler.setNextHandler(debugHandler);
debugHandler.setNextHandler(errorHandler);
infoHandler.handle("INFO: This is an informational message.");
infoHandler.handle("DEBUG: This is a debug message.");
infoHandler.handle("ERROR: This is an error message.");
}
}
在这个示例中,不同的日志级别由不同的处理者处理。客户端将请求传递给链的第一个处理者(InfoHandler
),如果InfoHandler
不能处理该请求(即日志级别不是INFO),则将该请求传递给下一个处理者(DebugHandler
),依此类推,直到找到能够处理该请求的处理者为止。
职责链模式通过引入处理者链的概念,实现了请求的发送者和接收者之间的解耦,提高了系统的灵活性和可扩展性。然而,它也存在一些缺点,如性能问题和调试困难等。在实际应用中,需要根据具体的业务场景和需求来选择是否使用职责链模式。
命令模式(Command Pattern)是一种行为设计模式,它将一个请求封装为一个对象,从而使得你可以用不同的请求对客户端进行参数化、对请求排队或记录请求日志,以及支持可撤销的操作。命令模式的核心在于将请求的调用者和执行者解耦,通过引入命令对象作为中间层来实现这一点。
Execute
方法。+-------------+ +-------------+ +-------------+
| Command |<------| ConcreteCmd |-------| Receiver |
+-------------+ +-------------+ +-------------+
| + Execute() | | - receiver | | + Action() |
+-------------+ | + Execute() | +-------------+
+-------------+
^
|
+-------------+
| Invoker |
+-------------+
| + Invoke() |
+-------------+
以下是一个简单的命令模式示例,以电视机为例:
// 命令接口
interface Command {
void execute();
}
// 接收者
class Television {
public void on() {
System.out.println("The television is on.");
}
public void off() {
System.out.println("The television is off.");
}
}
// 具体命令
class TurnOnTV implements Command {
private Television tv;
public TurnOnTV(Television tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.on();
}
}
class TurnOffTV implements Command {
private Television tv;
public TurnOffTV(Television tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.off();
}
}
// 调用者
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Television tv = new Television();
Command turnOnCommand = new TurnOnTV(tv);
Command turnOffCommand = new TurnOffTV(tv);
RemoteControl remote = new RemoteControl();
remote.setCommand(turnOnCommand);
remote.pressButton(); // 输出: The television is on.
remote.setCommand(turnOffCommand);
remote.pressButton(); // 输出: The television is off.
}
}
命令模式在需要实现复杂请求处理、支持撤销/重做功能、或需要记录请求日志的场景中非常有用。
职责链模式(Chain of Responsibility Pattern),又称责任链模式,是一种行为型设计模式。它通过将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求为止,从而避免了请求的发送者和接收者之间的耦合关系。以下是关于职责链模式的详细解释:
职责链模式定义了一个请求处理的框架,请求沿着处理者链进行传递,每个处理者都有机会处理该请求,如果某个处理者不能处理该请求,则将该请求传递给链中的下一个处理者。
职责链模式通常包含以下角色:
优点:
缺点:
职责链模式适用于以下场景:
以下是一个简单的职责链模式示例,假设有一个日志系统,需要根据不同的日志级别(如INFO、DEBUG、ERROR)将日志消息传递给不同的处理器:
// 抽象处理者
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handle(String logMessage);
}
// 具体处理者:INFO日志处理器
class InfoHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("INFO")) {
System.out.println("INFO Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 具体处理者:DEBUG日志处理器
class DebugHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("DEBUG")) {
System.out.println("DEBUG Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 具体处理者:ERROR日志处理器
class ErrorHandler extends Handler {
@Override
public void handle(String logMessage) {
if (logMessage.startsWith("ERROR")) {
System.out.println("ERROR Handler: " + logMessage);
} else {
if (nextHandler != null) {
nextHandler.handle(logMessage);
}
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Handler infoHandler = new InfoHandler();
Handler debugHandler = new DebugHandler();
Handler errorHandler = new ErrorHandler();
infoHandler.setNextHandler(debugHandler);
debugHandler.setNextHandler(errorHandler);
infoHandler.handle("INFO: This is an informational message.");
infoHandler.handle("DEBUG: This is a debug message.");
infoHandler.handle("ERROR: This is an error message.");
}
}
在这个示例中,不同的日志级别由不同的处理者处理。客户端将请求传递给链的第一个处理者(InfoHandler
),如果InfoHandler
不能处理该请求(即日志级别不是INFO),则将该请求传递给下一个处理者(DebugHandler
),依此类推,直到找到能够处理该请求的处理者为止。
职责链模式通过引入处理者链的概念,实现了请求的发送者和接收者之间的解耦,提高了系统的灵活性和可扩展性。然而,它也存在一些缺点,如性能问题和调试困难等。在实际应用中,需要根据具体的业务场景和需求来选择是否使用职责链模式。
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来减少内存使用和提高性能。它主要用于处理大量相似对象的场景,通过共享对象的相同部分来减少内存占用。
享元模式的核心思想是将对象的状态分为内部状态和外部状态:
享元模式通常包含以下几个角色:
享元模式适用于以下场景:
享元模式在软件开发中有广泛的应用,例如:
享元模式是一种有效的设计模式,它通过共享对象来减少内存使用和提高性能。然而,在使用享元模式时需要注意划分对象的内部状态和外部状态,并合理管理外部状态。同时,也需要根据具体的应用场景来评估是否适合使用享元模式。