软件设计模式与体系结构(简单工厂模式设计实验+工厂方法模式设计实验+抽象工厂模式设计实验)

本文介绍了如何使用简单工厂模式重构Java图表库,避免了大类和条件判断带来的问题,并展示了如何用抽象工厂模式改进界面皮肤库设计,提高灵活性和可扩展性。
摘要由CSDN通过智能技术生成

简单工厂模式设计实验

某软件公司欲基于Java 语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,例如柱状图、饼状图、折线图等。某软件公司图表库设计人员希望为应用系统开发人员提供一套灵活易用的图表库,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。

某软件公司图表库设计人员提出了一个初始设计方案,将所有图表的实现代码封装在一个Chart类中,其框架代码如下:

客户端代码通过调用 Chart 类的构造函数来创建图表对象,根据参数 type 的不同可以得到不同类型的图表,然后再调用 display() 方法来显示相应的图表。

不难看出,Chart 类是一个“巨大的”类,在该类的设计中存在以下几个问题:         (1)在 Chart 类中包含很多“if···else..”代码块,整个类的代码相当冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且大量条件语句的存在还将影响系统的性能,程序在执行过程中需要做大量的条件判断。

(2)Chart 类的职责过重,它负责初始化和显示所有的图表对象,将各种图表对象的初始化代码和显示代码集中在一个类中实现,违反了单一职责原则,不利于类的重用和维护,而且将大量的对象初始化代码都写在构造函数中将导致构造函数非常庞大,对象在创建时需要进行条件判断,降低了对象创建的效率。

(3)当需要增加新类型的图表时,必须修改 Chart 类的源代码违反了开闭原则。

(4)客户端只能通过 new 关键字来直接创建 Chart 对象,Chart 类与客户端类合度较高,对象的创建和使用无法分离。

(5)客户端在创建 Chart 对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色、高度等,如果在 Chart 类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设置,这些代码在每次创建 Chart 对象时都会出现,导致代码的重复。

面对上面的设计,请使用简单工厂模式对上面的代码进行重构。请给出设计类图,以及对应的 Java 代码(包括客户端的调用代码)

答案举例:

interface Chart {

    public void display();

}

class ChartFactory {

    public static Chart getChart(String type) {

        Chart chart = null;

        if (type.equalsIgnoreCase("histogram")) {

            chart = new HistogramChart();

            System.out.println("初始化设置柱状图!");

        }

        else if (type.equalsIgnoreCase("pie")) {

            chart = new PieChart();

            System.out.println("初始化设置饼状图!");

        }

        else if (type.equalsIgnoreCase("line")) {

            chart = new LineChart();

            System.out.println("初始化设置折线图!");            

        }

        return chart;

    }

}

class HistogramChart implements Chart {

    public HistogramChart() {

        System.out.println("创建柱状图!");

    }

   

    public void display() {

        System.out.println("显示柱状图!");

    }

}

class PieChart implements Chart {

    public PieChart() {

        System.out.println("创建饼状图!");

    }

   

    public void display() {

        System.out.println("显示饼状图!");

    }

}

class LineChart implements Chart {

    public LineChart() {

        System.out.println("创建折线图!");

    }

   

    public void display() {

        System.out.println("显示折线图!");

    }

}

class Client {

    public static void main(String args[]) {

        Chart chart;

        chart = ChartFactory.getChart("line");

        chart.display();

    }

}

工厂方法模式设计实验

某软件公司欲开发一个系统运行日志记录器(Logger)。该记录器可以通过多种途径保存系统的运行日志:例如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,某软件公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。如何封装记录器的初始化过程并保证多种记录器切换的灵活性是某软件公司开发人员面临的一个难题。

某软件公司的开发人员通过对该需求进行分析,发现该日志记录器有两个设计要点:

(1)需要封装日志记录器的初始化过程,这些初始化工作较为复杂,例如需要初始化其他相关的类,还有可能需要配置工作环境(例如连接数据库或创建文件),导致代码较长,如果将它们都写在构造函数中,会导致构造函数庞大,不利于代码的修改和维护。

(2)用户可能需要更换日志记录方式,在客户端代码中需要提供一种灵活的方式来选择日志记录器,尽量在不修改源代码的基础上更换或者增加日志记录方式。

某软件公司发人员最初使用简单工厂模式对日志记录器进行了设计,初始结构如下图所示。

在上图所示的设计中:LoggerFactory 充当创建日志记录器的工厂,提供了工厂方法 createLogger() 用于创建日志记录器,Logger 是抽象日志记录器接口,其子类为具体日志记录器。上面设计对应的代码如下:

  

为了突出设计重点,上述代码进行了简化,省略了具体日志记录器类的初始化代码。在 LoggerFactory 类中提供了静态工厂方法 createLogger() ,用于根据所传入的参数创建各种不同类型的日志记录器。通过使用简单工厂模式,将日志记录器对象的创建和使用分离,客户端只需使用由工厂类创建的日志记录器对象即可,无须关心对象的创建过程但是,虽然简单工厂模式实现了对象的创建和使用分离,仍然存在以下两个问题:

(1)工厂类过于庞大,包含了大量的 if···ese··· 代码,导致维护和测试难度增大

(2)系统扩展不灵活,如果增加新类型的日志记录器,必须修改静态工厂方法的业务逻辑,违反了开闭原则。

如何解决这两个问题,请使用工厂模式重构上面的设计。请给出设计类图,以及对应的 Java 代码(包括客户端的调用代码)

答案举例:

interface Logger {

    public void writeLog();

}

class DatabaseLogger implements Logger {

    public void writeLog() {

        System.out.println("数据库日志记录。");

    }

}

class FileLogger implements Logger {

    public void writeLog() {

        System.out.println("文件日志记录。");

    }

}

interface LoggerFactory {

    public Logger createLogger();

}

class DatabaseLoggerFactory implements LoggerFactory {

    public Logger createLogger() {

            Logger logger = new DatabaseLogger();

            return logger;

    }  

}

class FileLoggerFactory implements LoggerFactory {

    public Logger createLogger() {

            Logger logger = new FileLogger();

            return logger;

    }  

}

class Client {

    public static void main(String args[]) {

        LoggerFactory factory;

        Logger logger;

        factory = new FileLoggerFactory();

        logger = factory.createLogger();

        logger.writeLog();

    }

}

抽象工厂模式设计实验

某软件公司欲开发一套界面皮肤库,可以对 Java 桌面软件进行界面美化。为了保护版权,该皮肤库源代码不打算公开,而只向用户提供已打包为 jar 文件的 class 字节码文件。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素。其结构示意图如下图所示。

该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。

某软件公司的开发人员针对上述要求,决定使用工厂方法模式进行系统的设计。为了保证系统的灵活性和可扩展性,提供一系列具体工厂来创建按钮、文本框、组合框等界面元素,客户端针对抽象工厂编程,初始结构如下图所示。

上图中的产品抽象类和具体产品类代码如下:

Button.java

public interface Button {

    public void display();    

}

SpringButton.java

public class SpringButton implements Button{

    public void display(){

        System.out.println("显示浅绿色按钮");

    }    

}

SummerButton.java

 public class SummerButton implements Button{

    public void display(){

        System.out.println("显示浅蓝色按钮");

    }    

}

ComboBox.java

public interface ComboBox {

    public void display();

}

SpringComboBox.java

 public class SpringComboBox implements ComboBox{

    public void display(){

        System.out.println("显示绿色边框组合框");

    }    

}

SummerComboBox.java

 public class SummerComboBox implements ComboBox{

    public void display(){

        System.out.println("显示蓝色边框组合框");

    }    

}

TextField.java

 public interface TextField {

    public void display();    

}

SpringTextField.java

 public class SpringTextField implements TextField{

    public void display(){

        System.out.println("显示绿色边框文本框");

    }    

}

SummerTextField.java

 public class SummerTextField implements TextField{

    public void display(){

        System.out.println("显示蓝色边框文本框");

    }    

}

在上述的设计中,提供了大量工厂来创建具体的界面组件,可以通过配置文件更换具体界面组件从而改变界面风格。但是,此设计方案存在以下问题:

(1)当需要增加新的皮肤时,虽然不需要修改现有代码,但是需要增加大量类,针对每一个新增具体组件都需要增加一个具体工厂,类的个数成对增加,这无疑会导致系统越来越庞大,从而增加了系统的维护成本和运行开销。

(2)由于同一种风格的具体界面组件通常要一起显示,因此需要为每个组件都选择一个具体工厂,用户在使用时必须逐个进行设置,如果某个具体工厂选择失误将会导致界面显示混乱,虽然可以适当增加一些约束语句,但客户端代码和配置文件都较为复杂。如何减少系统中类的个数并保证客户端每次始终只使用某一种风格的具体界面组件?这是某软件公司开发人员所面临的两个问题。显然,工厂方法模式无法解决这两个问题。

请使用抽象工厂模式重构上面的设计。请给出设计类图,以及对应的 Java 代码(包括客户端的调用代码)

答案举例:

interface Button {

    public void display();

}

class SpringButton implements Button {

    public void display() {

        System.out.println("显示浅绿色按钮。");

    }

}

class SummerButton implements Button {

    public void display() {

        System.out.println("显示浅蓝色按钮。");

    }  

}

interface TextField {

    public void display();

}

class SpringTextField implements TextField {

    public void display() {

        System.out.println("显示绿色边框文本框。");

    }

}

class SummerTextField implements TextField {

    public void display() {

        System.out.println("显示蓝色边框文本框。");

    }  

}

interface ComboBox {

    public void display();

}

class SpringComboBox implements ComboBox {

    public void display() {

        System.out.println("显示绿色边框组合框。");

    }

}

class SummerComboBox implements ComboBox {

    public void display() {

        System.out.println("显示蓝色边框组合框。");

    }  

}

interface SkinFactory {

    public Button createButton();

    public TextField createTextField();

    public ComboBox createComboBox();

}

class SpringSkinFactory implements SkinFactory {

    public Button createButton() {

        return new SpringButton();

    }

    public TextField createTextField() {

        return new SpringTextField();

    }

    public ComboBox createComboBox() {

        return new SpringComboBox();

    }

}

class SummerSkinFactory implements SkinFactory {

    public Button createButton() {

        return new SummerButton();

    }

    public TextField createTextField() {

        return new SummerTextField();

    }

    public ComboBox createComboBox() {

        return new SummerComboBox();

    }

}

class Client {

    public static void main(String args[]) {

        SkinFactory factory;

        Button bt;

        TextField tf;

        ComboBox cb;

        factory = new SummerSkinFactory();

        bt = factory.createButton();

        tf = factory.createTextField();

        cb = factory.createComboBox();

        bt.display();

        tf.display();

        cb.display();

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值