策略模式的现实示例

发布于 2024-07-10 13:57:47 字数 267 浏览 7 评论 0原文

我一直在阅读有关 OCP 原则 以及如何使用策略模式来完成此任务。

我打算尝试向几个人解释这一点,但我能想到的唯一例子是根据“订单”的状态使用不同的验证类。

我在网上读过几篇文章,但这些文章通常不会描述使用该策略的真正相似的原因,例如生成报告/账单/验证等...

是否有任何您认为策略的真实示例模式常见吗?

I've been reading about the OCP principle and how to use the strategy pattern to accomplish this.

I was going to try and explain this to a couple of people, but the only example I can think of is using different validation classes based on what status an "order" is.

I've read a couple of articles online, but these don't usually describe a real alike reason to use the strategy, like generating reports/bills/validation, etc...

Are there any real-world examples where you think a strategy pattern is common?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

給妳壹絲溫柔 2024-07-17 13:57:47

怎么样:

你必须加密一个文件。

对于小文件,您可以使用“内存中”策略,其中读取整个文件并将其保存在内存中(假设文件<1 GB)对于

大文件,您可以使用另一种策略,其中读取文件的部分内容存储在内存中,部分加密结果存储在 tmp 文件中。

对于同一任务,这可能是两种不同的策略。

客户端代码看起来是一样的:

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



// implementations:
interface  Cipher  {
     public void performAction();
}

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

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

     Cipher c = CipherFactory.getCipher( file.size() );

返回密码的正确策略实例。

(我什至不知道 Cipher 是否是正确的词:P)

What about this:

You have to encrypt a file.

For small files, you can use "in memory" strategy, where the complete file is read and kept in memory ( let's say for files < 1 gb )

For large files, you can use another strategy, where parts of the file are read in memory and partial encrypted results are stored in tmp files.

These may be two different strategies for the same task.

The client code would look the same:

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



// implementations:
interface  Cipher  {
     public void performAction();
}

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

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

The

     Cipher c = CipherFactory.getCipher( file.size() );

Would return the correct strategy instance for the cipher.

( I don't even know if Cipher is the right word :P )

天邊彩虹 2024-07-17 13:57:47

同样,这是一篇旧帖子,但仍然出现在搜索中,因此我将添加另外两个示例(代码采用 C# 语言)。 我非常喜欢策略模式,因为当项目经理说:“我们希望应用程序执行‘X’,但‘X’尚不清楚,并且它可能在不久的将来发生变化时,它多次救了我的命。 ”
解释策略模式的视频以《星际争霸》为例。

属于此类别的东西:

  • 排序:我们想要对这些数字进行排序,但我们不知道是否要使用 BrickSort、BubbleSort 或其他排序

  • 验证:我们需要根据“某些规则”检查项目,但尚不清楚该规则是什么,我们可能会认为 。

  • 游戏:我们希望玩家在移动时能够行走或奔跑,但也许在未来,他还应该能够游泳、飞行、传送、在地下挖洞等。

  • 存储信息:我们希望应用程序将信息存储到数据库,但稍后它可能需要能够保存文件,或进行网络调用

  • 输出:我们需要将 X 输出为纯字符串,但稍后可能是 CSV、XML、JSON 等。


示例

我有一个项目,用户可以将产品分配给数据库中的人员。 将产品分配给某人的状态为“已批准”或“已拒绝”,这取决于某些业务规则。 例如:如果用户将产品分配给某个年龄的人,则该产品的状态应被拒绝; 如果项目中的两个字段之间的差异大于50,则其状态被拒绝等等。

现在,在开发阶段这些业务规则还没有完全清晰,并且随时可能出现新的规则。 策略模式的强大之处在于我创建了一个 RuleAgent,它给出了 IRules 列表。

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

在将产品分配给某人时,我创建一个 RuleAgent,为其提供一个规则列表(全部实现 IRule),并要求它验证分配。 它将贯穿所有规则。 其中,因为它们都实现相同的接口,所以都具有 IsApproved 方法,并且如果其中任何一个返回 false,则返回 false。

现在,例如,当经理突然出现并说,我们还需要拒绝所有实习生的分配,或所有加班人员的分配......你创建这样的新类:

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

你会发现你不必继续添加或者删除 if 语句或代码,只需创建一个实现 IRUle 接口的新规则类,并在需要时将其切换出来。


另一个很好的例子:Scott Allen 的视频系列,位于 http://www.asp.net/mvc/pluralsight 他在应用程序的单元测试部分使用策略模式。

他构建了一个网站,其中有一个页面根据受欢迎程度显示项目。 然而,“受欢迎”可以是很多东西(最多的浏览量、最多的订阅者、创建日期、最多的活动、最少的评论量等),并且如果管理层还不知道如何订购,并且可能想要尝试不同的方式稍后订购。 您使用 order 方法创建一个接口(IOrderAlgorithm 或其他东西),并让 Orderer 对象将排序委托给 IOrderAlgorithm 接口的具体实现。 您可以创建“CommentOrderer”、“ActivityOrderer”等...并在出现新需求时将其切换出去。

Again, an old post but still turns up on searches so I'll add two more examples (Code is in C#). I absolutely love the Strategy pattern since it has saved my butt a lot of times when the project managers say: "We want the application to do 'X', but 'X' is not yet clear and it can change in the near future."
This video explaining the strategy pattern, uses StarCraft as an example.

Stuff that falls in this category:

  • Sorting: We want to sort these numbers, but we don't know if we are gonna use BrickSort, BubbleSort or some other sorting

  • Validation: We need to check items according to "Some rule", but it's not yet clear what that rule will be, and we may think of new ones.

  • Games: We want player to either walk or run when he moves, but maybe in the future, he should also be able to swim, fly, teleport, burrow underground, etc.

  • Storing information: We want the application to store information to the Database, but later it may need to be able to save a file, or make a webcall

  • Outputting: We need to output X as a plain string, but later may be a CSV, XML, JSON, etc.


Examples

I have a project where the users can assign products to people in a database. This assignment of a product to a person has a status which is either "Approved" or "Declined", which is dependent on some business rules. For example: if a user assigns a product to a person with a certain age, it's status should be declined; If the difference between two fields in the item is larger than 50, it's status is declined, etc.

Now, at the moment of development these business rules are not yet all completely clear, and new rules could come up at any time. The power of the stragety-pattern is that I made a RuleAgent, which is given a list of IRules.

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

At the moment of assigning a product to a person, I create a RuleAgent, give it a list of rules (which all implement IRule), and ask it to validate an assignment. It'll run through all it's rules. Which, because they all implement the same interface, all have the IsApproved method and return false if any of them returns false.

Now when for instance the manager suddenly comes up and says, we also need to decline all assignments to interns, or all assignments to people working overtime... You make new classes like this:

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

You see that you don't have to keep adding or removing if-statements or code, just make a new rule-class that implements the IRUle interface and switch those out when needed.


Another great example: Scott Allen's video series at http://www.asp.net/mvc/pluralsight where he uses the strategy pattern in the Unit-test part of the application

He builds a website which has a page that displays items based on popularity. However "Popular" can be many things (most views, most subscribers, creation date, most activity, least amount of comments, etc), and in case management doesn't yet know exactly how to order, and may want to experiment with different orderings at a later date. You make an interface (IOrderAlgorithm or something) with an order method, and let an Orderer-object delegate the ordering to a concrete implementation of the IOrderAlgorithm interface. You can make a "CommentOrderer", "ActivityOrderer", etc... And just switch these out when new requirements come up.

凹づ凸ル 2024-07-17 13:57:47

要点:

策略是行为设计​​模式。 它用于在算法系列之间进行切换。

一个真实的例子:航空公司在某些月份(7 月至 12 月)提供折扣。 您可以拥有一个票价模块,该模块根据月份数决定定价选项。

看一个简单的例子。 该示例可以扩展到在线零售应用程序,该应用程序可以轻松地在特殊日子/欢乐时光为购物车商品提供折扣。

import java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}

/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy {
    public String getName() { 
        return this.getClass().getName();
    }
    public double getDiscountPercentage() {
        return 0;
    }
}

/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy {
    public String getName() {
        return this.getClass().getName();
    }
    public double getDiscountPercentage() {
        return 0.25;
    }
}

/* Context , which is optional can be single interface for client. */
class StrategyContext {

    double price; // price for some item or air ticket etc.
    Map<String, OfferStrategy> strategyContext = new HashMap<String, OfferStrategy>();

    StrategyContext(double price) {
        this.price = price;
        strategyContext.put(NoDiscountStrategy.class.getName(), new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(), new QuarterDiscountStrategy());
    }

    public void applyStrategy(OfferStrategy strategy) {
        /*
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation
        */
        System.out.println("Price before offer :" + price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:" + finalPrice);
    }

    public OfferStrategy getStrategy(int monthNo) {
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if (monthNo < 6)  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }
        else {
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }
    }
}

public class StrategyDemo {
    public static void main(String args[]) {
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month =" + month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }
}

输出:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0

Key notes:

Strategy is behavioral design pattern. It is used to switch between family of algorithms.

One real word example : Airlines offering discounts during some months (July-December). You can have one Fare module, which decides pricing options depending on month number.

Have a look at a simple example. This example can be extended to on-line retailing applications, which provides discount to shopping cart items on special days/happy hours easily.

import java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}

/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy {
    public String getName() { 
        return this.getClass().getName();
    }
    public double getDiscountPercentage() {
        return 0;
    }
}

/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy {
    public String getName() {
        return this.getClass().getName();
    }
    public double getDiscountPercentage() {
        return 0.25;
    }
}

/* Context , which is optional can be single interface for client. */
class StrategyContext {

    double price; // price for some item or air ticket etc.
    Map<String, OfferStrategy> strategyContext = new HashMap<String, OfferStrategy>();

    StrategyContext(double price) {
        this.price = price;
        strategyContext.put(NoDiscountStrategy.class.getName(), new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(), new QuarterDiscountStrategy());
    }

    public void applyStrategy(OfferStrategy strategy) {
        /*
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation
        */
        System.out.println("Price before offer :" + price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:" + finalPrice);
    }

    public OfferStrategy getStrategy(int monthNo) {
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if (monthNo < 6)  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }
        else {
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }
    }
}

public class StrategyDemo {
    public static void main(String args[]) {
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month =" + month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }
}

output:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0
旧时光的容颜 2024-07-17 13:57:47

我可以想到几个相当简单的例子:

  • 对列表进行排序。 该策略是用于确定列表中的两个项目中的哪一个是“第一个”的比较。
  • 您可能有一个应用程序,其中可以在运行时选择排序算法本身(QuickSort、HeapSort 等)
  • < a href="http://logging.apache.org/log4net/release/manual/introduction.html" rel="noreferrer">Log4Net 和 Log4j
  • 布局管理器 在 UI 工具包中
  • 数据压缩。 您可能有一个 ICompressor 接口,其唯一方法如下所示:

    字节[]压缩(字节[]输入);

    您的具体压缩类可能是 RunLengthCompression、DeflateCompression 等。

I can think of several fairly simple examples:

  • Sorting a list. The strategy is the comparison used to decide which of two items in the list is "First"
  • You might have an application where the sorting algorithm itself (QuickSort, HeapSort, etc.) may be chosen at runtime
  • Appenders, Layouts, and Filters in Log4Net and Log4j
  • Layout Managers in UI toolkits
  • Data compression. You might have an ICompressor interface whose sole method looks something like this:

    byte[] compress(byte[] input);

    Your concrete compression classes might be things like RunLengthCompression, DeflateCompression, etc.

故事未完 2024-07-17 13:57:47

策略模式的一个常见用法是定义自定义排序策略(在没有高阶函数的语言中),例如在 Java 中按长度对字符串列表进行排序,传递一个匿名内部类(策略接口的实现)

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

:以类似的方式,策略可以用于对象数据库的本机查询,例如在 db4o 中:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});

One common usage of the strategy pattern is to define custom sorting strategies (in languages without higher-order functions), e.g. to sort a list of strings by length in Java, passing an anonymous inner class (an implementation of the strategy interface):

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

In a similar manner, strategies can be used for native queries with object databases, e.g. in db4o:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});
败给现实 2024-07-17 13:57:47

我有一个应用程序,每天将其用户群与我们的企业目录同步。 用户是否符合资格取决于他们在大学的身份。 每天,配置程序都会进行一次,并确保那些应该符合资格的人在应用程序中得到配置,而那些不符合资格的人则被取消配置(实际上是根据优雅的降级算法,但这不是重点)。 周六,我进行了更彻底的更新,同步每个用户的一些属性并确保他们具有适当的资格。 在月底,我会根据当月的使用情况进行一些帐单处理。

我使用可组合策略模式来执行此同步。 主程序基本上根据星期几(仅同步更改/同步所有)和相对于校历的学期时间来选择主策略。 如果计费周期即将结束,那么它还会将其与计费策略组合起来。 然后它通过标准接口运行所选策略。

我不知道这种情况有多常见,但我觉得它非常适合策略模式。

I have an application that synchronizes it's user base each day against our enterprise directory. User's are eligible or not eligible based on their status in the University. Each day the provisioning program goes through and makes sure that those who are supposed to be eligible are provisioned in the application and those who are not are de-provisioned (actually according to a graceful degradation algorithm, but that's beside the point). On Saturday I do a more thorough update that synchronizes some properties of each user as well as making sure that they have the proper eligibility. At the end of the month I do some bill back processing based on usage for that month.

I use a composable strategy pattern to do this synchronization. The main program basically chooses a master strategy depending on the day of the week (sync changes only/sync all) and the time of semester relative to the academic calendar. If the billing cycle is ending, then it also composes it with a billing strategy. It then runs the chosen strategy via a standard interface.

I don't know how common this is, but I felt like it was a perfect fit for the strategy pattern.

染火枫林 2024-07-17 13:57:47

策略模式的一个很好的例子是在游戏中,我们可以有不同的角色,每个角色可以有多种武器来攻击,但一次只能使用一种武器。 所以我们有角色作为上下文,例如国王,指挥官,骑士,士兵
武器作为一种策略,其中 Attack() 可以是取决于所使用的武器的方法/算法。 因此,如果具体的武器类是 Sword、Axe、Crossbow、BowAndArrow 等……它们都会实现 Attack() 方法。 我确信不需要进一步的解释。

A good example of strategy pattern would be in a game where we can have different characters and each character can have multiple weapons to attack but at a time can use only one weapon. So we have the character as the context, for example King, Commander, Knight ,Soldier
and weapon as a strategy where attack() could be the method/algorithm which depends on the weapons being used. So if the concrete weapon classes were Sword, Axe, Crossbow, BowAndArrow etc .. they would all implement the attack() method. I am sure further explanation is not needed.

滴情不沾 2024-07-17 13:57:47

我知道这是一个老问题,但我认为我最近实现了另一个有趣的例子。

这是文档交付系统中使用的策略模式的一个非常实际的示例。

我有一个 PDF 交付系统,它接收包含大量文档和一些元数据的档案。 根据元数据,它决定将文档放在哪里; 比如说,根据数据,我可以将文档存储在 ABC 存储系统中,或三者的混合中。

不同的客户使用该系统,并且在出现错误时有不同的回滚/错误处理要求:一个人希望交付系统在第一个错误时停止,将所有已交付的文档保留在其存储中,但停止该过程并且不交付任何其他内容; 另一位希望在存储到 C 时出现错误时从 B 回滚,但保留已交付给 A 的内容。 很容易想象第三个或第四个也会有不同的需求。

为了解决这个问题,我创建了一个基本的交付类,其中包含交付逻辑,以及从所有存储回滚内容的方法。 在发生错误时,交付系统实际上不会直接调用这些方法。 相反,该类使用依赖注入来接收“回滚/错误处理策略”类(基于使用系统的客户),该类在出现错误时被调用,如果适合该策略,该类又会调用回滚方法。

交付类本身向策略类报告发生的情况(哪些文档被交付到哪些存储,以及发生了哪些故障),并且每当发生错误时,它都会询问策略是否继续。 如果策略说“停止它”,则该类将调用该策略的“cleanUp”方法,该方法使用先前报告的信息来决定从交付类中调用哪些回滚方法,或者干脆不执行任何操作。

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

因此,我现在有两种不同的策略:一种是 QuitterStrategy(在出现第一个错误时退出并且不清除任何内容),另一种是 MaximizeDeliveryToAStrategy(它会尝试尽可能多的策略)尽可能不中止进程,并且永远不会回滚传送到存储A的内容,但如果传送到C失败,则回滚B中的内容)。

根据我的理解,这是策略模式的一个例子。 如果您(是的,您正在阅读)认为我错了,请在下面发表评论并告诉我。 我很好奇什么构成了策略模式的“纯粹”使用,以及我的实现的哪些方面违反了定义。 我觉得它看起来有点搞笑,因为策略界面有点胖。 到目前为止我看到的所有例子都只使用了一种方法,但我仍然认为这封装了一种算法(如果一段业务逻辑可以被认为是一种算法,我认为它确实如此)。

由于该策略还会在交付执行期间收到有关事件的通知,因此它也可以被视为观察者,但那是另一个故事了。

经过一点研究,这似乎是一种称为 顾问。 它是关于是否应该继续交付的顾问,但它也是一个主动的错误处理程序,因为它可以在需要时回滚内容。

无论如何,这是一个相当复杂的示例,可能会让您感觉策略模式的用法都太简单/愚蠢了。 当与其他模式一起使用时,它可能非常复杂,甚至更适用。

I know this is an old question, but I think I have another interesting example that I implemented recently.

This is a very practical example of the strategy pattern being used in a document delivery system.

I had a PDF delivery system which received an archive containing lots of documents and some metadata. Based on the metadata, it decided where to put the document in; say, depending on the data, I could store the document in A, B, or C storage systems, or a mix of the three.

Different customers used this system, and they had different rollback / error handling requirements in case of errors: one wanted the delivery system to stop on the first error, leave all documents already delivered in their storages, but stop the process and not deliver anything else; another one wanted it to rollback from B in case of errors when storing in C, but leave whatever was already delivered to A. It's easy to imagine that a third or fourth one will also have different needs.

To solve the problem, I have created a basic delivery class that contains the delivery logic, plus methods for rolling back stuff from all storages. Those methods are not actually called by the delivery system directly in case of errors. Instead, the class uses Dependency Injection to receive a "Rollback / Error Handling Strategy" class (based on the customer using the system), which is called in case of errors, which in turn calls the rollback methods if it's appropriate for that strategy.

The delivery class itself reports what's going on to the strategy class (what documents were delivered to what storages, and what failures happened), and whenever an error occurs, it asks the strategy whether to continue or not. If the strategy says "stop it", the class calls the strategy's "cleanUp" method, which uses the information previously reported to decide which rollback methods to call from the delivery class, or simply do nothing.

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

So I now have two different strategies: one is the QuitterStrategy (which quits on the first error and cleans up nothing) and the other one is the MaximizeDeliveryToAStrategy (which tries as much as possible not to abort the process and never rollback stuff delivered to storage A, but rollbacks stuff from B if delivery to C fails).

From my understanding, this is one example of the strategy pattern. If you (yes, you reading) think I'm wrong, please comment below and let me know. I'm curious as to what would constitute a "pure" use of the strategy pattern, and what aspects of my implementation violate the definition. I think it looks a bit funny because the strategy interface is a bit fat. All examples I've seen so far use only one method, but I still think this encapsulates an algorithm (if a piece of business logic can be considered an algorithm, which I think it does).

Since the strategy is also notified about events during the delivery execution, it can also be considered an Observer, but that's another story.

From doing a little research, it seems like this is a "composite pattern" (like MVC, a pattern that uses multiple design patterns underneath in a particular way) called the Advisor. It's an advisor on whether the delivery should continue or not, but it's also an active error handler since it can rollback stuff when asked to.

Anyways, this is a quite complex example that might make that feeling of yours that usages of the strategy pattern are all too simple / silly. It can be really complex and even more applicable when used together with other patterns.

几度春秋 2024-07-17 13:57:47

策略模式是最常用的模式,专门用于验证和排序算法。

让我用一个简单的实际示例来解释

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

这个测试代码是

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

相同的示例取自 http://coder2design.com /策略模式/

Strategy pattern is most commonly used pattern specially for validations and sorting algorithms.

Let me explain with a simple practical example

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

The test code for this is

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

Same example is taken from http://coder2design.com/strategy-pattern/

忘你却要生生世世 2024-07-17 13:57:47
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by paypal
        cart.pay(new PaypalStrategy("[email protected]", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by paypal
        cart.pay(new PaypalStrategy("[email protected]", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
椒妓 2024-07-17 13:57:47

您确定“订单”的状态不是状态模式吗? 我有预感,订单不会根据其状态进行不同的处理。

以订单上的运送方法为例:

order.Ship();
  • 如果运送方式在
    其状态的函数,那么你就
    得到了一个策略模式。
  • 然而如果
    Ship() 方法仅成功
    订单付款后,以及
    订单尚未发货,
    你有一个状态模式。

我发现的状态模式(和其他模式)的最好例子是在书“Head第一个设计模式”,这太神奇了。
紧随其后的是David Cumps 的博客系列模式

Are you sure that the status of an "order" is not a State pattern? I have a hunch that an order will not be handled differently depending on its status.

Take for example the method Ship on the Order:

order.Ship();
  • If the shipping method varies in
    function of its status, then you've
    got a strategy pattern.
  • If however
    the Ship() method succeeds only
    when the order has been paid, and
    the order has not been shipped yet,
    you've got a state pattern.

The best example of the state pattern (and other patterns) I found was in the book "Head First Design Patterns", which is amazing.
A close second will be David Cumps' blogging series of patterns.

末蓝 2024-07-17 13:57:47

计算商品 GST 税总额的示例

public interface TaxCalculation {

    public Double calculateTax(Double price);  
}
public class FivePercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        
        Double dbl = (price*5)/100;
        return dbl;
    }

}
public class EighteenPercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        Double dbl = (price*18)/100;
        return dbl;
    }

}
public class Item {

    public String name;
    public Double price;
    public int taxRate;
    public Double totalTax;
    
    public Item(String name, Double price, int taxRate) {
        super();
        this.name = name;
        this.price = price;
        this.taxRate = taxRate;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public int getTaxRate() {
        return taxRate;
    }

    public void setTaxRate(int taxRate) {
        this.taxRate = taxRate;
    }

    public Double getTotalTax() {
        return totalTax;
    }

    public void setTotalTax(Double totalTax) {
        this.totalTax = totalTax;
    }

    public void calculateTax(TaxCalculation taxcalulation, Double price) {
        this.totalTax = taxcalulation.calculateTax(price);
    }
    
    @Override
    public String toString() {
        return "Items [name=" + name + ", price=" + price + ", taxRate=" + taxRate + ", totalTax=" + totalTax + "]";
    }
    
}
public class CalculateTax {

    public static void main(String[] args) {
        
        List<Item> itemList = new ArrayList<>();
        
        Item item1 = new Item("Engine Oil", 320.0, 5);
        Item item2 = new Item("Painting", 3500.00, 18);
        
        itemList.add(item1);
        itemList.add(item2);
        
        itemList.stream().forEach(x-> {
            if(x.getTaxRate() == 5) {
                x.calculateTax(new FivePercentage(), x.getPrice());
            } else if(x.getTaxRate() == 18) {
                x.calculateTax(new EighteenPercentage(), x.getPrice());
            }
        });
        
        itemList.stream().forEach(x-> {
            System.out.println(x.toString());
        });
    }
}

Example to calculate Item GST Tax Total

public interface TaxCalculation {

    public Double calculateTax(Double price);  
}
public class FivePercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        
        Double dbl = (price*5)/100;
        return dbl;
    }

}
public class EighteenPercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        Double dbl = (price*18)/100;
        return dbl;
    }

}
public class Item {

    public String name;
    public Double price;
    public int taxRate;
    public Double totalTax;
    
    public Item(String name, Double price, int taxRate) {
        super();
        this.name = name;
        this.price = price;
        this.taxRate = taxRate;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public int getTaxRate() {
        return taxRate;
    }

    public void setTaxRate(int taxRate) {
        this.taxRate = taxRate;
    }

    public Double getTotalTax() {
        return totalTax;
    }

    public void setTotalTax(Double totalTax) {
        this.totalTax = totalTax;
    }

    public void calculateTax(TaxCalculation taxcalulation, Double price) {
        this.totalTax = taxcalulation.calculateTax(price);
    }
    
    @Override
    public String toString() {
        return "Items [name=" + name + ", price=" + price + ", taxRate=" + taxRate + ", totalTax=" + totalTax + "]";
    }
    
}
public class CalculateTax {

    public static void main(String[] args) {
        
        List<Item> itemList = new ArrayList<>();
        
        Item item1 = new Item("Engine Oil", 320.0, 5);
        Item item2 = new Item("Painting", 3500.00, 18);
        
        itemList.add(item1);
        itemList.add(item2);
        
        itemList.stream().forEach(x-> {
            if(x.getTaxRate() == 5) {
                x.calculateTax(new FivePercentage(), x.getPrice());
            } else if(x.getTaxRate() == 18) {
                x.calculateTax(new EighteenPercentage(), x.getPrice());
            }
        });
        
        itemList.stream().forEach(x-> {
            System.out.println(x.toString());
        });
    }
}
荒芜了季节 2024-07-17 13:57:47

我在一个应用程序的相当复杂的引擎中使用了策略方法,这是一个很好的例子。 本质上,引擎的作用是首先找到拥有小部件的人员列表,第二个作用是根据未知数量的参数(例如之前业务的价格距离)找出拥有小部件的 10 名最佳人员。 ,库存金额,运输选项等等等...)

本质上我们所做的是将问题分为两种策略,第一个是数据检索,因为我们知道我们的小部件有多个来源,并且我们需要能够获取数据并将其转换为通用结构。

然后我们还意识到,我们有多种算法,其中一些是基于参数加权的,另一些则非常奇怪和适当,如果不拿出 visios 和图表,我就无法公正地对待它们,好吧,你明白了,我们有很多算法选择最优秀的人才。

我们的服务本身本质上定义了输入、输出并对数据进行了一些标准化,它还使用提供者模式来插入使用该策略的应用程序特定数据提供者和算法提供者。 这是一个相当有效的系统。

我们对是否使用策略或模板模式进行了一些争论,但我们从未解决过。

I used the strategy approach in a fairly complex engine in an application that is a good example. Essentially the engine's role was to go and first find a list of people who had a widget, it's second role was to figure out which were the 10 best people with a widget based on an unknown number of parameters (things like price distance previous business together, ammount on stock, shipping options etc etc etc...)

Essentially what we did was we broke the problem into two strategies the first being data retrieval, as we knew that we had multiple sources of our widgets and we needed to be able to get the data and transform it to a common structure.

We then also realized that we had multiple algorithims some were based on weighting the parameters, others were very weird and propitery and I couldn't do them justice without pulling out visios and charts and well you get the picture, we had lots of algorithims for selecting the best people.

Our service itself was very thing it essentially defined the inputs, outputs and did some normalization of the data, it also used a provider pattern to plug-in the application specific data providers and algorithim providers which used the strategy. This was a fairly effective system.

We had some debates if we were using a strategy or a template pattern which we never resolved.

絕版丫頭 2024-07-17 13:57:47

假设您想要编写一个算法来计算给定月份和年份的第 n 个 Xday,例如 2014 年 10 月的第二个星期一。您想要使用 Android 的 Time 类 android.text。 format.Time 来表示日期,但您还想编写一个也适用于 java.util.Calendar 的通用算法。

这就是我所做的。

在 DatetimeMath.java 中:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

在 TimeMath.java 中:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

在 OrdinalDayOfWeekCalculator.java 中,具有通用算法的类:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

在我的 Android 应用程序中,我会调用类似的内容

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

如果我想为 java.util.Calendar< 重用相同的算法/code>,我只需编写一个类 CalendarMath 来实现 DatetimeMath 中的三个方法,然后使用

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);

Let's say you want to write an algorithm to calculate the nth Xday of a given month and year, e.g., the second Monday of October 2014. You want to use Android's Time class android.text.format.Time to represent the date, but you also want to write a generic algorithm that can also apply to java.util.Calendar.

This is what I did.

In DatetimeMath.java:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

In TimeMath.java:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

In OrdinalDayOfWeekCalculator.java, the class with the generic algorithm:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

In my Android app, I would call something like

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

If I want to reuse the same algorithm for java.util.Calendar, I would just write a class CalendarMath that implements the three methods in DatetimeMath and then use

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);
我是男神闪亮亮 2024-07-17 13:57:47

几周前,我添加了一个通用 Java 接口,该接口由我们的域对象之一实现。 该域对象是从数据库加载的,数据库表示是一个具有大约 10 多个分支的星型模式。 拥有如此重量级的域对象的后果之一是,我们必须创建代表相同模式的其他域对象,尽管重量级较小。 所以我让其他轻量级对象实现相同的接口。 换句话说,我们有:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

最初,我想使用 CollectibleElephant 来对 Elephant 进行排序。 很快,我的队友就开始使用 CollectibleElephant 来运行安全检查,在它们发送到 GUI 时对其进行过滤等。

A few weeks ago, I added a common Java interface which was implemented by one of our domain objects. This domain object was loaded from the database, and the database representation was a star schema with about 10+ branches. One of the consequences of having such a heavy weight domain object is that we've had to make other domain objects that represented the same schema, albeit less heavyweight. So I made the other lightweight objects implement the same interface. Put otherwise we had:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

Originally, I wanted to use CollectibleElephant to sort Elephants. Pretty quickly, my teammates glommed onto CollectibleElephant to run security checks, filter them as they get sent to the GUI, etc.

花心好男孩 2024-07-17 13:57:47

我们必须为具有非常复杂数据库的企业平台创建第三方配置接口。 要配置的数据的提交是作为我们的数据类型的列表,这些数据类型被放入应用程序的优先级队列中,以便由于依赖关系,它们可以以正确的顺序写入数据库。

写入该数据的过程非常简单,不断从优先级队列的顶部弹出,然后根据提取的对象的类型选择策略。

We had to create a third-party provisioning interface for an enterprise platform with a very complicated database. The submission of data to be provisioned was as a list of our data types which were put into a priority queue in our application so they could be written to the database in the correct order due to dependencies.

The process to write that data was then quite simple, keep popping off the top of the priority queue and then choose a strategy based on the type of the object that you extract.

原来是傀儡 2024-07-17 13:57:47

来自维基百科

在计算机编程中,策略模式(也称为策略模式)是一种行为软件设计模式,可以在运行时选择算法。 代码不是直接实现单个算法,而是接收运行时指令,了解要使用一系列算法中的哪些算法

在 Windows Paint 应用程序中,您可以看到一个策略模式,您可以在其中在不同部分中独立选择形状和颜色。 这里的形状和颜色是可以在运行时改变的算法。

如果您想用红色绘制一个圆圈,他们不会提供“RedCircle”选项,而是让您选择圆圈和您选择的颜色。

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

如果没有策略模式,形状和颜色的笛卡尔积会增加类的数量。 每个实现的接口也会发生变化。

From wikipedia

In computer programming, the strategy pattern (also known as the policy pattern) is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use

In Windows Paint application you can see a strategy pattern where you can choose the shape and color independently in a different sections. Here the shape and color are the algorithms which can changed at runtime.

If you want to draw a circle with red color, rather than providing an option of 'RedCircle' they let you choose the circle and a color of your choice.

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

Without strategy pattern will increase the number of classes with the Cartesian product of shape and color. Also the interface changes for each implementation.

日暮斜阳 2024-07-17 13:57:47

例如,想象一下有人工智能敌人的射击游戏。
你希望他们根据发生的情况以不同的方式持续战斗..
使用策略模式,您可以连续循环并动态更改特定操作或操作的执行方式。

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}

Imagine a shooter game with AI enemies for example.
You want them to continuously fight in different ways based on what happens ..
With strategy pattern you can continuously loop and dynamically change how a specific or action will be performed.

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
幸福%小乖 2024-07-17 13:57:47

这个答案是针对初学者并希望通过最简单的示例来理解这一点的人 - (参考:Headfirst Design Patterns)

#include<iostream>
using namespace std;

/*
    Where it is applicable?
    The selection of an algorithm is required from a family of algorithms.
    To avoid multiple conditional statements for selection of algorithms
    and to hide its algorithm data structures and complexity from client.
*/

class Fly {
public:
    virtual void fly() = 0;
};

//concrete Fly : rocketFly
class rocketFly : public Fly {
public:
    void fly() {
        cout <<"rocketFly::fly()" << endl;
    }
};

//concrete Fly : normalFly
class normalFly : public Fly {
public:
    void fly() {
        cout <<"normalFly::fly()" << endl;
    }
};

//Duck "HAS A" relationship with Fly
class Duck {
private:
    //Duck has a Fly behavour
    Fly* flyObj;
public:
    Duck(Fly* obj) : flyObj(obj) {
        
    }

    void DuckFly() {
        flyObj->fly();
    }
};

int main() {
    rocketFly* rObj = new rocketFly;
    Duck wildDuck(rObj);
    wildDuck.DuckFly();

    normalFly* nObj = new normalFly;
    Duck cityDuck(nObj);
    cityDuck.DuckFly();

    /*
        I didn't have to create classes like wildDuck which inherits from Duck and they implement their own
        fly, quack etc behaviour. There will be code duplication.
        So, instead of that, create an interface of fly, make concrete fly classes with different
        fly behaviour. Use objects to any of these concrete classes to inject to one generic duck
        class which will automatically call correct fly behaviour.
    */

return 0;
}

This answer is for someone who is a beginner and want to understand this with the simplest example possible - (Reference : Headfirst Design Patterns)

#include<iostream>
using namespace std;

/*
    Where it is applicable?
    The selection of an algorithm is required from a family of algorithms.
    To avoid multiple conditional statements for selection of algorithms
    and to hide its algorithm data structures and complexity from client.
*/

class Fly {
public:
    virtual void fly() = 0;
};

//concrete Fly : rocketFly
class rocketFly : public Fly {
public:
    void fly() {
        cout <<"rocketFly::fly()" << endl;
    }
};

//concrete Fly : normalFly
class normalFly : public Fly {
public:
    void fly() {
        cout <<"normalFly::fly()" << endl;
    }
};

//Duck "HAS A" relationship with Fly
class Duck {
private:
    //Duck has a Fly behavour
    Fly* flyObj;
public:
    Duck(Fly* obj) : flyObj(obj) {
        
    }

    void DuckFly() {
        flyObj->fly();
    }
};

int main() {
    rocketFly* rObj = new rocketFly;
    Duck wildDuck(rObj);
    wildDuck.DuckFly();

    normalFly* nObj = new normalFly;
    Duck cityDuck(nObj);
    cityDuck.DuckFly();

    /*
        I didn't have to create classes like wildDuck which inherits from Duck and they implement their own
        fly, quack etc behaviour. There will be code duplication.
        So, instead of that, create an interface of fly, make concrete fly classes with different
        fly behaviour. Use objects to any of these concrete classes to inject to one generic duck
        class which will automatically call correct fly behaviour.
    */

return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文