应对软件需求变化-生成器模式的应用

零、使用动机

在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成。

由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定

如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?

一、软件需求

需要创建一个手机对象,手机对象由手机名称、屏幕、电池、操作系统、触控笔这些子对象生成。手机的构造算法是稳定的,变化频率较低的。电池、操作系统等是易变的,经常会有新的电池、新的操作系统。

二、具体实现

对于一个软件系统,最开始只有一个需求没有变化或者看不到变化趋势时,可以不使用设计模式。随着需求的变化,可以发现哪些是变化点,哪些是稳定点,然后有针对性的使用对应的设计模式。

针对当前系统的需求,手机的构造算法是稳定的,各个部分的实现是易变的,可以使用生成器模式来进行实现。

1、产品

手机作为产品类。手机对象的生成需要由多个子对象构成。

// 这是"Product"产品类
public class MobilePhone {
    // 部件类型
    private String phoneName;
    private ScreenType phoneScreen;
    private Battery phoneBattery;
    private OperatingSystem phoneOS;
    private Stylus phoneStylus;

    // region 访问手机组件的getter/setter公开方法
    public MobilePhone(String name) {
        this.phoneName = name;
    }

    public String getPhoneName() {
        return phoneName;
    }

    public ScreenType getPhoneScreen() {
        return phoneScreen;
    }

    public void setPhoneScreen(ScreenType phoneScreen) {
        this.phoneScreen = phoneScreen;
    }

    public Battery getPhoneBattery() {
        return phoneBattery;
    }

    public void setPhoneBattery(Battery phoneBattery) {
        this.phoneBattery = phoneBattery;
    }

    public OperatingSystem getPhoneOS() {
        return phoneOS;
    }

    public void setPhoneOS(OperatingSystem phoneOS) {
        this.phoneOS = phoneOS;
    }

    public Stylus getPhoneStylus() {
        return phoneStylus;
    }

    public void setPhoneStylus(Stylus phoneStylus) {
        this.phoneStylus = phoneStylus;
    }
    // endregion

    @Override
    public String toString() {
        return String.format("Name: %s\nScreen: %s\nBattery: %s\nOS: %s\nStylus: %s\n", this.phoneName,
                this.phoneScreen, this.phoneBattery, this.phoneOS, this.phoneStylus);
    }
}

各个组成部分。

电池:

// 电池容量
public enum Battery {
    MAH_1000,
    MAH_1500,
    MAH_2000
}

屏幕类型:

// 屏幕类型
public enum ScreenType {
    SCREENTYPE_TOUCH_CAPACITIVE, // 电容式
    SCREENTYPE_TOUCH_RESISTIVE, // 电阻式
    SCREENTYPE_NON_TOUCH
}

操作系统:

// 操作系统
public enum OperatingSystem {
    ANDROID,
    WINDOWS_MOBILE,
    WINDOWS_PHONE,
    SYMBIAN
}

触控笔:

// 触控笔
public enum Stylus {
    YES,
    NO
}

2、构建者

构建者封装产品的各个部分的构建,以及产品的获取。构建者提供的各个组成部分的构建接口是相对稳定的。构建者提供公共接口和具体构建者的实现。具体构建者对每个组成部分的构建接口提供具体构建者的个性化的实现。

构建者接口:

// 这个是构建者"Builder"接口
public interface IMobilePhoneBuilder {
    void buildScreen();
    void buildBattery();
    void buildOS();
    void buildStylus();
    MobilePhone getPhone();
}

安卓手机具体构建者:

// 安卓手机具体构建者"ConcreteBuilder"
public class AndroidPhoneBuilder implements IMobilePhoneBuilder {
    
    private MobilePhone phone;

    public AndroidPhoneBuilder() {
        this.phone = new MobilePhone("Android Phone");
    }
    
    @Override
    public void buildScreen() {
        phone.setPhoneScreen(ScreenType.SCREENTYPE_TOUCH_RESISTIVE);
    }

    @Override
    public void buildBattery() {
        phone.setPhoneBattery(Battery.MAH_1500);
    }

    @Override
    public void buildOS() {
        phone.setPhoneOS(OperatingSystem.ANDROID);
    }

    @Override
    public void buildStylus() {
        phone.setPhoneStylus(Stylus.YES);
    }

    // 获得最终构建出来的产品
    @Override
    public MobilePhone getPhone() {
        return this.phone;
    }
}

Windows手机具体构建者:

// Windows手机具体构建者"ConcreteBuilder"
public class WindowsPhoneBuilder implements IMobilePhoneBuilder  {

    private MobilePhone phone;
    
    public WindowsPhoneBuilder() {
        this.phone = new MobilePhone("Windows Phone");
    }
    
    @Override
    public void buildScreen() {
        phone.setPhoneScreen(ScreenType.SCREENTYPE_TOUCH_CAPACITIVE);
    }

    @Override
    public void buildBattery() {
        phone.setPhoneBattery(Battery.MAH_2000);
    }

    @Override
    public void buildOS() {
        phone.setPhoneOS(OperatingSystem.WINDOWS_PHONE);
    }

    @Override
    public void buildStylus() {
        phone.setPhoneStylus(Stylus.NO);
    }

    @Override
    public MobilePhone getPhone() {
        return this.phone;
    }

}

 

3、导演

导演对这个复杂对象的生成逻辑进行一个组装和编排,生成逻辑是相对稳定的。

// 这个是导演"Director"
public class Manufacturer {
    public void construct(IMobilePhoneBuilder phoneBuilder) {
        phoneBuilder.buildBattery();
        phoneBuilder.buildOS();
        phoneBuilder.buildScreen();
        phoneBuilder.buildStylus();
    }
}

4、调用方

客户程序作为调用方,生成具体的复杂对象。可以通过配置指定具体的创建者,和客户程序解耦。

// 客户程序
public class ClassicBuilderMain {

    public static void main(String[] args) {
        // 先创建导演Director
        Manufacturer manufacturer = new Manufacturer();
        // 先准备Builder接口
        IMobilePhoneBuilder phoneBuilder = null;
        
        // 制造一部安卓手机
        phoneBuilder = new AndroidPhoneBuilder();
        manufacturer.construct(phoneBuilder);
        String output = String.format("A new Phone built:\n\n%s", phoneBuilder.getPhone().toString());
        System.out.println(output);
        
        // 制造一部Windows手机
        phoneBuilder = new WindowsPhoneBuilder();
        manufacturer.construct(phoneBuilder);
        output = String.format("A new Phone built:\n\n%s", phoneBuilder.getPhone().toString());
        System.out.println(output);
    }
}

三、总结

生成器模式的使用场景:对于一个复杂的产品的创建,由哪些部分组成、构建步骤是相对稳定的,各个部分的具体实现是易变的、变化频率较快的。

 

posted @ 2020-06-02 19:42  windpoplar  阅读(255)  评论(0编辑  收藏  举报