从问题角度来思考设计模式(2) – 结构编

来源:互联网 发布:js复制一个对象 编辑:程序博客网 时间:2024/05/17 01:19

目录

  1. 生成编

让API返回信息适配多样性

  • 改造前
FooAPI fooAPI = new FooAPI(lat, lng);FooPlace place = new FooPlace();place.setAddress(fooAPI.getPostalCode() + " " + fooAPI.getAddress()); // 邮编 **市**区place.setStation(    new StringJoiner(",")    .add(fooAPI.getStation1())    .add(fooAPI.getStation2())    .add(fooAPI.getStation3())    .toString());  //A车站,B车站,C车站
上面代码是API返回信息整形用例。这里只使用了FooAPI,未来如果返回信息的整形方式不变的话,倒也没有什么问题。但从易维护的角度思考,这称不上一个好的设计。
  • 改造后Adapter
public class FooAPIAdapter {    private final FooAPI fooAPI;    public FooAPIAdapter(double latitude, double longitude) {        this.fooAPI = new FooAPI(latitude, longitude);    }    public String getAddress() {        return fooAPI.getPostalCode() + " " + fooAPI.getAddress();    }    public String getStation() {        return new StringJoiner(",")                .add(fooAPI.getStation1())                .add(fooAPI.getStation2())                .add(fooAPI.getStation3())                .toString();    }}
FooAPIAdapter fooAPI = new FooAPIAdapter(lat, lng);FooPlace place = new FooPlace();place.setAddress(fooAPI.getAddress());place.setStation(fooAPI.getStation());
在这里引入了Adapter(适配器)的概念。当返回信息的整形方式改变的时候,只要修改对应的Adapter类就可以,而对调用方不会产生代码改动。引入设计模式的初衷都为了,业务上的解耦,让代码更聚焦。

让API调用方不需要考虑操作顺序

  • 改造前
public class FooSorter {    private List<FooStudent> students = new List<>();    public void add(FooStudent student) {        students.add(student);    }    public void sort() {        students.sort(                Comparator.comparingInt(                        student -> student.getChineseScore()                                + student.getMathScore()                                + student.getEnglishScore())                        .reversed());    }    public List<FooStudent> getResult() {        return students;    }}
FooSorter sorter = new FooSorter();sorter.add(student1);sorter.add(student2);sorter.add(student3);sorter.sort();sorter.getResult();
需要遵循实例生成 -> add() -> sort() -> getResult()流程来调用,调用方如果不知道流程则调用失败,故这样的设计并不好。
  • 改造后Facade
public class FooSorter {    private List<FooStudent> students = new List<>();    private FooSorter() {}    public static List<FooStudent> sort(FooStudent... students) {        for (FooStudent student : students)            add(student);        sort();        return getResult();    }    private void add(FooStudent student) {        students.add(student);    }    private void sort() {        students.sort(                Comparator.comparingInt(                        student -> student.getChineseScore()                                + student.getMathScore()                                + student.getEnglishScore())                        .reversed());    }    private List<FooStudent> getResult() {        return students;    }}
FooSorter.sort(student1, student2, student3);
调用方不需要知道排序逻辑,且调用代码行数也缩减1行。涉及多个类按顺序执行复杂的处理时,可以考虑使用Facade模式。常见的有,手机的一键静音模式,该模式包括了音量设置,振动器设置等。玩魔兽世界的玩家肯定更熟悉,就是传说中的一键宏,惩戒骑用脸滚键盘的回忆有木有。

让同级类的结果组合起来

  • 改造前
public class FooPosition {    private int x;    private int y;    public void moveAs(FooMove move) {        move.move(this);    }}public abstract class FooMove {    private final int addition;    public FooMove(int addition) {        this.addition = addition;    }    public abstract void move(FooPosition position);}public class FooMoveHorizontal extends FooMove {    public FooMoveHorizontal(int addition) {        super(addition);    }    @Override    public void move(FooPosition position) {        position.setX(position.getX() + addition);    }}public class FooMoveVertical extends FooMove {    public FooMoveVertical(int addition) {        super(addition);    }    @Override    public void move(FooPosition position) {        position.setY(position.getY() + addition);    }}
FooMove moveHorizontal = new FooMoveHorizontal(x);FooMove moveVertical = new FooMoveVertical(y);FooPosition position = new FooPosition();position.moveAs(moveHorizontal);position.moveAs(moveVertical);
上面的代码本身设计没有什么问题,但每次都只能往一个方向,要么水平要么垂直方向移动。如何实现一次调用能达到同时操作x,y呢?
  • 改造后Decorator
public class FooPosition {    private int x;    private int y;    public void moveAs(FooMove move) {        move.move(this);    }}public abstract class FooMove {    private final int addition;    private final FooMove move;    public FooMove(int addition) {        this.addition = addition;    }    public FooMove(int addition, FooMove move) {        this.addition = addition;        this.move = move;    }    public abstract void move(FooPosition position);}public class FooMoveHorizontal extends FooMove {    public FooMoveHorizontal(int addition) {        super(addition);    }    public FooMoveHorizontal(int addition, FooMove move) {        super(addition, move);    }    @Override    public void move(FooPosition position) {        if (move != null)            move.move(position);        position.setX(position.getX() + addition);    }}public class FooMoveVertical extends FooMove {    public FooMoveVertical(int addition) {        super(addition);    }    public FooMoveVertical(int addition, FooMove move) {        super(addition, move);    }    @Override    public void move(FooPosition position) {        if (move != null)            move.move(position);        position.setY(position.getY() + addition);    }}
FooMove move = new FooMoveHorizontal(x, new FooMoveVertical(y));FooPosition position = new FooPosition();position.moveAs(move);
x,y移动的距离汇总到move这个实例中。且利用这个设计,当移动结束时,还想再水平移动时只需要简单的new FooMoveHorizontal(x, move)就可以。有兴趣的朋友可以思考下左左右右上上下下如何用类来生成?

根据条件不同控制权限

  • 改造前
public class FooTestUser extends FooUser {    @Override    public void foo1() {        // NormalUser foo1    }    @Override    public void foo2() {        throw new RuntimeException("this operation is not permitted.");    }    @Override    public void foo3() {        throw new RuntimeException("this operation is not permitted.");    }}public class FooNormalUser extends FooUser {    @Override    public void foo1() {        // NormalUser foo1    }    @Override    public void foo2() {        // NormalUser foo2    }    @Override    public void foo3() {        throw new RuntimeException("this operation is not permitted.");    }}public class FooSuperUser extends FooUser {    @Override    public void foo1() {        // SuperUser foo1    }    @Override    public void foo2() {        // SuperUser foo2    }    @Override    public void foo3() {        // foo3    }}
TestUser只能执行NormalUser类中的foo1方法,执行foo2foo3方法时会报错。从上面的代码可以发现TestUserNormalUserfoo1代码内容是一样,返回了dry(Don't repeat yourself)原则。
  • 改造后Proxy
public class FooTestUser extends FooUser {    private FooUser normalUser = new FooNormalUser();    @Override    public void foo1() {        normalUser.foo1();    }    @Override    public void foo2() {        throw new RuntimeException("this operation is not permitted.");    }    @Override    public void foo3() {        throw new RuntimeException("this operation is not permitted.");    }}NormalUser和SuperUser类保持不变
通过Proxy模式,控制对某个对象的访问。如果需要,可以给不同的用户提供不同级别的使用权限。

查看原文:http://www.huuinn.com/archives/301
更多技术干货:风匀坊
关注公众号:风匀坊
原创粉丝点击