写代码啦
策略模式和工厂模式的实践
回复数(0) 浏览数(140)
{{topic.upvote_count || 0}} 编辑 回复

策略模式

策略模式可以定义为,定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
基于一个简单的例子来看一下,假设我们明天中午吃饭有三种选择,泡面,订外卖,煮饺子。要做选择可以这么做
首先定义一个接口

interface Lunch{
public void eat();
}

具体的实现类如下
```
public class InstantNoodle implements Lunch{
public void eat(){
//eat InstantNoodle;
}
}

public class TakeAway implements Lunch{
public void eat(){
//eat takeaway;
}
}

public class Dumplings implements Lunch{
public void eat(){
//eat dumplings;
}
}

其实这时候而言,我们的功能已经算完成了。为了保证选择的封装性,便捷切换以及良好的扩展性,我们可以为他增加一个封装类,在策略模式中通常叫做Context。

public class Context{
private Lunch lunch = null;
public Context(Lunch lunch){
this.lunch = lunch;
}
private void toEat(){
lunch.eat();
}
}
```

这时候如果第二天我选择我要吃的东西就可以使用如下方式:

public class Main{
public static void main(String[] args) {
//想吃泡面
Context context = Context(new InstantNoodle());
context.eat();
}
}

对于策略模式而言,我们可以使用如下的类图来进行表示:
策略模式 策略模式

优势与缺点

优点
  • 算法可以自由的切换
  • 避免多重条件的判断
  • 扩展性好
缺点
  • 策略种类多
  • 策略类需要对外暴漏

应用场景

在JDK中的ThreadPoolExecutor使用了策略模式,它预定了4中策略:

ThreadPoolExecutor.AbortPolicy()
ThreadPoolExecutor.CallerRunsPolicy()
ThreadPoolExecutor.DiscardOldestPolicy()
ThreadPoolExecutor.DiscardPolicy()

可以看到每个策略都被放在一个单独的类中
```
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }

    /**
     * Always throws RejectedExecutionException.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     * @throws RejectedExecutionException always
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

### 工厂模式
这里不再举例实际的工厂例子,实际的例子可以参照我的[这篇文章](https://www.jianshu.com/p/524c94aeaeb6)。

### 特征和优缺点
我们知道工厂模式可以分为简单工厂模式,工厂方法模式和抽象工厂模式,我们简单来讨论下他们的特点和优缺点。
##### 简单工厂模式
优点是比较简单,简化了类的创建过程。
缺点是工厂类的扩展比较困难,不符合开闭原则。
##### 工厂方法模式
工厂方法模式是典型的解耦框架,在new一个对象的地方可以替换,所以在所有需要生成对象的地方都可以使用。
![工厂方法模式](https://upload-images.jianshu.io/upload_images/4926805-6cd90421090f6daf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 *使用案例*
1.如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SQL语句是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。

2.在实际的单元测试应用中,如果要测试一下代码
Class TestA{  
     public int test(){  
         DoSomeThing dst = new DoSomeThing();  
          dst.run();  
     }  
}  
因为方法体创建的对象使用一般的Mockito是不能进行mock的,这时候我们可以构造一个工厂方法。

Class Factory{

public DoSomeThing build(){

return new DoSomeThing ();

}

}

新的代码可以写为

Class TestB{

Factory factory = new Factory();

public int test(){

DoSomeThing s = factory.build();

s.run();

}

}
```
这样便可以进行mock,顺利完成单元测试。

抽象工厂方法

抽象工厂 抽象工厂

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

抽象工厂方法的优势
- 封装性
- 产品族内的约束为非公开状态

应用场景
例如一个应用,需要在三个不同平台(Windows、Linux、Android),通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。

策略模式

策略模式可以定义为,定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
基于一个简单的例子来看一下,假设我们明天中午吃饭有三种选择,泡面,订外卖,煮饺子。要做选择可以这么做
首先定义一个接口

interface Lunch{
public void eat();
}

具体的实现类如下
```
public class InstantNoodle implements Lunch{
public void eat(){
//eat InstantNoodle;
}
}

public class TakeAway implements Lunch{
public void eat(){
//eat takeaway;
}
}

public class Dumplings implements Lunch{
public void eat(){
//eat dumplings;
}
}

其实这时候而言,我们的功能已经算完成了。为了保证选择的封装性,便捷切换以及良好的扩展性,我们可以为他增加一个封装类,在策略模式中通常叫做Context。

public class Context{
private Lunch lunch = null;
public Context(Lunch lunch){
this.lunch = lunch;
}
private void toEat(){
lunch.eat();
}
}
```

这时候如果第二天我选择我要吃的东西就可以使用如下方式:

public class Main{
public static void main(String[] args) {
//想吃泡面
Context context = Context(new InstantNoodle());
context.eat();
}
}

对于策略模式而言,我们可以使用如下的类图来进行表示:
策略模式 策略模式

优势与缺点

优点
  • 算法可以自由的切换
  • 避免多重条件的判断
  • 扩展性好
缺点
  • 策略种类多
  • 策略类需要对外暴漏

应用场景

在JDK中的ThreadPoolExecutor使用了策略模式,它预定了4中策略:

ThreadPoolExecutor.AbortPolicy()
ThreadPoolExecutor.CallerRunsPolicy()
ThreadPoolExecutor.DiscardOldestPolicy()
ThreadPoolExecutor.DiscardPolicy()

可以看到每个策略都被放在一个单独的类中
```
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }

    /**
     * Always throws RejectedExecutionException.
     *
     * @param r the runnable task requested to be executed
     * @param e the executor attempting to execute this task
     * @throws RejectedExecutionException always
     */
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

### 工厂模式
这里不再举例实际的工厂例子,实际的例子可以参照我的[这篇文章](https://www.jianshu.com/p/524c94aeaeb6)。

### 特征和优缺点
我们知道工厂模式可以分为简单工厂模式,工厂方法模式和抽象工厂模式,我们简单来讨论下他们的特点和优缺点。
##### 简单工厂模式
优点是比较简单,简化了类的创建过程。
缺点是工厂类的扩展比较困难,不符合开闭原则。
##### 工厂方法模式
工厂方法模式是典型的解耦框架,在new一个对象的地方可以替换,所以在所有需要生成对象的地方都可以使用。
![工厂方法模式](https://upload-images.jianshu.io/upload_images/4926805-6cd90421090f6daf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 *使用案例*
1.如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SQL语句是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。

2.在实际的单元测试应用中,如果要测试一下代码
Class TestA{  
     public int test(){  
         DoSomeThing dst = new DoSomeThing();  
          dst.run();  
     }  
}  
因为方法体创建的对象使用一般的Mockito是不能进行mock的,这时候我们可以构造一个工厂方法。

Class Factory{

public DoSomeThing build(){

return new DoSomeThing ();

}

}

新的代码可以写为

Class TestB{

Factory factory = new Factory();

public int test(){

DoSomeThing s = factory.build();

s.run();

}

}
```
这样便可以进行mock,顺利完成单元测试。

抽象工厂方法

抽象工厂 抽象工厂

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

抽象工厂方法的优势
- 封装性
- 产品族内的约束为非公开状态

应用场景
例如一个应用,需要在三个不同平台(Windows、Linux、Android),通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。

140
回复 编辑