战略模板的实际使用

在面向对象的程序设计中使用模板(或模式)源于这样的愿望:使代码更简单,更可靠,并且不想浪费时间,并且允许组织者通过不同程度的培训有效地合作,从而为他们提供了在业务逻辑概念框架中理解源代码的单一基础应用程序。这意味着学习设计模式是程序员专业发展的关键步骤。

如何学习设计模式?有两种方法:无聊和可理解(您喜欢我的分类吗?)。一种无聊的方法涉及使用抽象示例对一系列模式进行学术研究。就我个人而言,我更喜欢相反的情况-一种可理解的方法,当将任务设置为相对较高的表达水平时,您就可以选择设计模式。尽管可以将两种方法结合使用。

那走吧

策略模板是指一组行为模板。

策略模板的简要定义


当对象根据其内部状态的变化更改其行为时,该模板用于在一系列算法之间切换。

应用策略模板的实际示例


  • 排序:我们想对这些数字进行排序,但是我们不知道是否要使用BrickSort,BubbleSort或其他任何排序方式。例如,您有一个网站,页面上会根据受欢迎程度显示元素。但是,许多事情可以是“受欢迎的”(大多数视图,大多数订户,创建日期,大多数活动,最少评论)。如果管理层尚不清楚确切的下订单方式,并且可能想在以后使用不同的订单,则可以使用order方法创建一个接口(IOrderAlgorithm或其他东西),并允许Orderer对象委托IOrderAlgorithm接口的具体实现的顺序。您可以创建CommentOrderer,ActivityOrderer等,只需在出现新需求时将其关闭即可。
  • 从异构对象处理队列(队列处理和保存数据):一个示例是代理系统,该代理系统累积来自不同数据源的对象,然后从队列中提取对象并保存后,由选择策略根据该对象的属性确定。
  • 验证方式 我们需要根据“某些规则”检查元素,但是尚不清楚该规则将是什么,我们可以想到新的规则。
  • 身份验证:在基本,摘要,OpenID,OAuth方案之间选择一种身份验证策略。

这是一个例子:

interface AuthStrategy {
    auth(): void;
}
class Auth0 implements AuthStrategy {
    auth() {
        log('Authenticating using Auth0 Strategy')
    }
}
class Basic implements AuthStrategy {
    auth() {
        log('Authenticating using Basic Strategy')
    }
}
class OpenID implements AuthStrategy {
    auth() {
        log('Authenticating using OpenID Strategy')
    }
}

class AuthProgram {
    private _strategy: AuthStrategy
    use(strategy: AuthStrategy) {
        this._strategy = strategy
        return this
    }
    authenticate() {
        if(this._strategy == null) {
            log("No Authentication Strategy set.")
        }
        this._strategy.auth()
    }
    route(path: string, strategy: AuthStrategy) {
        this._strategy = strategy
        this.authenticate()
        return this
    }
}

  • (games): — , , , , , , , . , , , , . «», «», «» Attack() . , «», «», «», « » Attack ().
  • (storing information): , , -. , PDF, , . , ; , , A, B C, . PDF , / PDF. , , , , , , B C, , A. , . PDF, , , . . Dependency Injection « / » ( , ), , , , , . , ( , ), , , , . « », «cleanUp» , , , , .
  • (outputting): X , CSV, XML, JSON .
  • (invoicing): - , , - .
  • (navigation): .
  • (logging): Log4Net Log4j , Appenders, Layouts, and Filters.
  • 加密:对于小文件,当读取整个文件并将其存储在内存中时(例如,对于<1 GB的文件),可以使用内存策略。对于大文件,可以使用不同的策略,其中部分文件在内存中读取,部分加密的结果存储在tmp文件中。对于同一任务,这可以是两种不同的策略。

这是一个例子:

//   ""
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             //   byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             //     .... 
         }

}

//   
File file = getFile();
Cipher c = CipherFactory.getCipher( file.size());
c.performAction();

  • 图形编辑器:例如,在Windows Paint应用程序中,有一个策略模板的实现,您可以在其中独立选择不同部分的形状和颜色。在这里,形状和颜色是可以在运行时更改的算法。

Shape redCircle = new RedCircle(); //    «»
Shaped redCircle = new Shape("red","circle"); //   «»

SOLID和策略模板的实施


“策略”模板解决的主要问题是什么?实际上,这是平面代码IF ...的替代。关于……对象的实现。

肮脏的平面代码示例(错误):

class Document {...}
class Printer {
    print(doc: Document, printStyle: Number) {
        if(printStyle == 0 /*   */) {
            // ...
        }
        if(printStyle == 1 /*  */) {
            // ...            
        }
        if(printStyle == 2 /*     */) {
            // ...
        }
        if(printStyle == 3 /*     */) {
            // ...            
        }
        if(printStyle == 4 /*     */) {
            // ...
        }
        // ...
    }
}

与“策略”模板相同的代码的示例(正确):

class Document {...}
interface PrintingStrategy {
    printStrategy(d: Document): void;
}
class ColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log(" ")
        // ...
    }
}
class InvertedColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log("  ")
        // ...
    }
}
class Printer {
    private printingStrategy: PrintingStrategy
    print(doc: Document) {
        this.printingStrategy.printStrategy(doc)
    }
}

这是基于SOLID的战略模板正确实施的另一个示例

//  /
interface LockOpenStrategy {
    open();
    lock();
}
//      
class RetinaScannerLockOpenStrategy implements LockOpenStrategy {
    open() {
        //...
    }
    lock() {
        //...
    }
}

//       
class KeypadLockOpenStrategy implements LockOpenStrategy {
    open() {
        if(password != ""){
            log("Entry Denied")
            return
        }
        //...
    }
    lock() {
        //...
    }
}
//        .
abstract class Door {
    public lockOpenStrategy: LockOpenStrategy
}
//   .
class GlassDoor extends Door {}
//    .
class MetalDoor extends Door {}
//       .
class DoorAdapter {
    openDoor(d: Door) {
        d.lockOpenStrategy.open()
    }
}

以下是逻辑的实际编码。

var glassDoor = new GlassDoor(); //   
glassDoor.lockOpenStrategy = new RetinaScannerLockOpenStrategy(); //         
var metalDoor = new MetalDoor(); //     
metalDoor.lockOpenStrategy = new KeypadLockOpenStrategy(); //      .
var door1 = new DoorAdapter().openDoor(glassDoor); //    . 
var door2  = new DoorAdapter().openDoor(metalDoor); //    . 

正如您在上面看到的,这是一个完全面向对象的代码,不包括IF ...过程样式否则.........或开关... 案件 ...

顺便说一句,为什么我们使用适配器类?门本身不会打开,一方面总是打开,另一方面,在打开门之前或打开完成后可能会发生一些事件,例如,BeforeOpen()和AfterOpen(),也可以链接到适配器。

重构和策略模板


当您开始注意到重复的算法时,应该使用策略模板,但是会有不同的变化。因此,有必要将算法分为几类,并根据需要在程序中填充它们。

此外,如果您发现同级算法周围有重复的条件语句。
大多数类具有关联行为时。然后,您需要选择它并将它们移到单独的类。

我希望这些示例选择可以帮助您适当地使用“策略”模板。
如果您能在评论中提供此模板的更多示例,我将感到高兴。

编码愉快,朋友和同事们!

Source: https://habr.com/ru/post/undefined/


All Articles