设计模式第一次作业

1.题目1

要求:某系统日志记录器要求支持多种日志记录方式,如文件记录、数据库记录等;用户可以根据要求动态选择日志记录方式。使用Factory模式来设计;如果系统中增加一个日志记录方式—控制台日志记录(ConsoleLog),类图将如何改变?

解答

根据工厂模式设计以下类图:

实现代码如下:

// 抽象日志工厂类
public abstract class LogFactory {
    abstract Log createLog();
}
// 文本日志工厂类
public class TextLogFactory extends LogFactory {
    @Override
    Log createLog() {
        return new TextLog();
    }
}
// 数据库日志工厂类
public class DBLogFactory extends LogFactory {
    @Override
    Log createLog() {
        return new DBLog();
    }
}
// 抽象日志产品类
public abstract class Log {
    abstract void add();
    abstract void delete();
    abstract void query();
}
// 文本日志产品类
public class TextLog extends Log {
    @Override
    void add() {
        System.out.println("add a text log");
    }

    @Override
    void delete() {
        System.out.println("delete a text log");
    }

    @Override
    void query() {
        System.out.println("query a text log");
    }
}

用户调用代码如下:

LogFactory factory = new TextLogFactory(); // 根据用户要求动态选择Factory具体类
Log log = factory.createLog();
log.add();

如果系统中增加一个日志记录方式—控制台日志记录,类图改变如下:

2.题目2

要求:某系统为了改进数据库操作的性能,自定义数据连接对象Connection和语句对象Statement,可针对不同类型的数据库提供不同的连接对象和语句对象;用户可以通过配置文件等方式根据实际需要动态更换系统数据库;使用Abstract Factory模式来设计。

解答

类图如下:

代码实现如下:

// 数据库抽象工厂类
public abstract class DBFactory {
    public abstract Connection makeConnection();
    public abstract Statement makeStatement();
}
// 数据库连接抽象产品类
public abstract class Connection {
    public abstract void connect();
}
// 数据库语句抽象产品类
public abstract class Statement {
    public abstract void query();
}
// MySql数据库连接
public class MySqlConnection extends Connection {
    @Override
    public void connect() {
        System.out.println("connect to mysql");
    }
}
// MySql数据库语句
public class MySqlStatement extends Statement {
    @Override
    public void query() {
        System.out.println("make a mysql query");
    }
}
// MySql数据库工厂类
public class MySqlDBFactory extends DBFactory {
    @Override
    public Connection makeConnection() {
        return new MySqlConnection();
    }

    @Override
    public Statement makeStatement() {
        return new MySqlStatement();
    }
}

用户调用如下:

DBFactory factory = new MySqlDBFactory(); // 可以根据配置文件更换为具体的数据库工厂类
Connection connection = factory.makeConnection();
Statement statement = factory.makeStatement();
connection.connect();
statement.query();

3.题目3

要求:KFC套餐是一个复杂对象,一般包括主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)组成部分,不同套餐有不同组成部分;KFC服务员要根据顾客要求,装配这些组成部分,构造一个完整套餐,返回给顾客;使用Builder模式来设计。

解答

类图如下:

代码如下:

// 套餐创建者抽象类
public abstract class ComboBuilder {
    protected Combo combo;

    public ComboBuilder() {
        this.combo = new Combo();
    }

    public Combo getCombo() {
        return combo;
    }

    public abstract void buildStaple();
    public abstract void buildDrink();
}
// 套餐导演抽象类
public abstract class ComboDirector {
    protected ComboBuilder builder;

    public ComboDirector(ComboBuilder builder) {
        this.builder = builder;
    }

    public abstract Combo construct();
}
// 套餐导演具体类,同时创建主食和饮料
public class ComboDoubleDirector extends ComboDirector {

    public ComboDoubleDirector(ComboBuilder builder) {
        super(builder);
    }

    @Override
    public Combo construct() {
        builder.buildStaple();
        builder.buildDrink();
        return builder.getCombo();
    }
}
// 套餐创建者具体类,创建各个part(即主食和饮料)
public class FamilyComboBuilder extends ComboBuilder {
    @Override
    public void buildStaple() {
        combo.add("Hamburger");
    }

    @Override
    public void buildDrink() {
        combo.add("Coke");
    }
}
// 套餐产品类
public class Combo {

    private ArrayList<String> foods = new ArrayList<>();

    public void add(String food) {
        foods.add(food);
    }

    public void show(){
        for (String food : foods) {
            System.out.println(food);
        }
    }
}

用户调用如下:

ComboBuilder builder = new FamilyComboBuilder();  // 指定具体的创建者类
ComboDirector director = new ComboDoubleDirector(builder); // 指定具体的组合规则类
             
Combo combo = director.construct();;       // 导演类按照类定义的规则组合各个part
combo.show();

4.题目4

要求:游戏中的地图:包括天空、地面、背景;人物包括人体、服装、装备等组成部分,如采用Builder模式如何设计?

解答

类图如下:

代码如下:

// 地图创建者抽象类
public abstract class MapBuilder {
    protected Map map;

    public MapBuilder() {
        this.map = new Map();
    }

    public Map getMap() {
        return map;
    }

    public abstract void buildSky();
    public abstract void buildGround();
    public abstract void buildBackground();
}
// 沙漠地图创建者具体类
public class DesertMapBuilder extends MapBuilder {
    @Override
    public void buildSky() {
        map.setSky("gray");
    }

    @Override
    public void buildGround() {
        map.setGround("sand");
    }

    @Override
    public void buildBackground() {
        map.setBackground("yellow");
    }
}
// 地图导演类
public class MapDirector {
    private MapBuilder builder;

    public MapDirector(MapBuilder builder) {
        this.builder = builder;
    }

    public Map construct() {
        builder.buildSky();
        builder.buildGround();
        builder.buildBackground();
        return builder.getMap();
    }
}

用户调用如下:

MapBuilder builder = new DesertMapBuilder();        // 指定具体的创建者类
MapDirector director = new MapDirector(builder);    // 指定具体的组合规则类

Map map =  director.construct();
map.show();

Factory模式和Builder模式的对比

从创建出来的产品进行分析,Factory最终创建单一产品,而观察Builder可以发现,其最终也只产生一个产品,但是该产品比较复杂,是一个复合产品,由多个零件构成。如第4题,如果使用Factory模式,单个Factory只能单一产生天空、地面或背景,而一个Builder能分别创建三个零件,创建后零件的组合规则是在Director类中定义,Builder最终产生一个完整的Map。所以,当一个产品构成比较复杂,可能复合了多个零件,但用户不想了解每个零件的生成过程,他最终只想要一个完整的产品,那么就应该采用Builder模式。而当用户最终需要的产品比较简单,可以将该产品看成是Builder模式下的一个part,这时就应该使用Factory模式了,因为用户就很有可能会更换这个产品的实现。

5.题目5

要求:某系统需要提供一个加密模块,将用户信息(如密码等)加密之后再存储在数据库中,系统已经定义好数据库操作类。为了提高开发效率,现要重用已有的加密算法,这些算法由第三方提供,没有源码。如采用Adapter模式如何设计?

解答

类图如下:

代码如下:

// Target
public abstract class Encryption {
    public abstract String encrypt(String str);
}
// Adapter
public class EncryptionAdapter extends Encryption {
    private ThirdPartyEncryption adaptee;

    public EncryptionAdapter(ThirdPartyEncryption adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public String encrypt(String str) {
        return adaptee.encrypt(str);
    }
}

用户调用如下:

Encryption encryption = new EncryptionAdapter(adaptee);
encryption.encrypt(str);

posted on 2017-11-02 23:23  蔡鸟一斤  阅读(509)  评论(0编辑  收藏  举报

导航