rooobot / architecture-training

Architecture training camp homework
0 stars 2 forks source link

架构师训练营-第三周练习作业1&作业2 #7

Open rooobot opened 4 years ago

rooobot commented 4 years ago

以下为练习作业1作业2:(助教要求打开链接直接能看到内容,所以就把两个练习作业放在一起了,因为提交作业的那里,练习作业只有一个链接)

作业1:手写单例模式,拍照提交:

image

照片有点模糊,手工重新编码如下:

public class Singleton {

    private Singleton() {}

    public static Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

}

作业2:使用组合设计模式编写程序:

Displayble接口:定义display()方法,用于输出实现者要显示的详细信息。

public interface Displayble {

    /**
     * Display detail info
     */
    void display();

}

GuiComponent接口:getName()方法返回组件对象的名称,同样继承了Displayble接口,具有输出组件GUI组件的显示详细信息的功能。

public interface GuiComponent extends Displayble {

    /**
     * Gui component's name
     * @return name
     */
    String getName();

}

WinForm组件:

public class WinForm implements GuiComponent {

    private String name;
    private List<GuiComponent> subComponents = new ArrayList<>();

    public WinForm(String name) {
        this.name = name;
    }

    @Override
    public void display() {
        System.out.println("print WinForm(" + getName() + ")");
        for (GuiComponent sub : subComponents) {
            sub.display();
        }
    }

    @Override
    public String getName() {
        return name;
    }

    public WinForm addSubComponent(GuiComponent component) {
        this.subComponents.add(component);
        return this;
    }
}

Picture组件:

public class Picture implements GuiComponent {

    private String name;

    public Picture(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print Picture(" + getName() + ")");
    }
}

Button组件:

public class Button implements GuiComponent {

    private String name;

    public Button(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print Button(" + getName() + ")");
    }
}

Frame组件:

public class Frame implements GuiComponent {

    private String name;
    private List<GuiComponent> subComponents = new ArrayList<>();

    public Frame(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print Frame(" + getName() + ")");
        for (GuiComponent sub : subComponents) {
            sub.display();
        }
    }

    public Frame addSubComponent(GuiComponent component) {
        this.subComponents.add(component);
        return this;
    }
}

Label组件:

public class Label implements GuiComponent {

    private String name;

    public Label(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print Label(" + getName() + ")");
    }
}

TextBox组件:

public class TextBox implements GuiComponent {

    private String name;

    public TextBox(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print TextBox(" + getName() + ")");
    }
}

PasswordBox组件:

public class PasswordBox implements GuiComponent {

    private String name;

    public PasswordBox(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print PasswordBox(" + getName() + ")");
    }
}

CheckBox组件:

public class CheckBox implements GuiComponent {

    private String name;

    public CheckBox(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print CheckBox(" + getName() + ")");
    }
}

LinkLabel组件:

public class LinkLabel implements GuiComponent {

    private String name;

    public LinkLabel(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void display() {
        System.out.println("print LinkLabel(" + getName() + ")");
    }
}

App:构建WinForm组件对象,输出WinForm组件对象的渲染信息(使用Builder模式构建)。

public class App {

    public static void main(String[] args) {
        // build WinForm with builder
        buildWinFormWithBuilder();
    }

    private static void buildWinFormWithoutBuilder() {
        // build WinForm
        WinForm winForm = new WinForm("WINDOW窗口");
        // build Picture
        Picture picture = new Picture("LOGO图片");
        winForm.addSubComponent(picture);
        // build Login Button
        Button loginBtn = new Button("登录");
        winForm.addSubComponent(loginBtn);
        // build Register Button
        Button registerBtn = new Button("注册");
        winForm.addSubComponent(registerBtn);
        // build Frame
        Frame frame = new Frame("FRAME1");
        winForm.addSubComponent(frame);
        // build username Label
        Label usernameLabel = new Label("用户名");
        frame.addSubComponent(usernameLabel);
        // build username TextBox
        TextBox usernameTextBox = new TextBox("用户名文本框");
        frame.addSubComponent(usernameTextBox);
        // build password Label
        Label passwordLabel = new Label("密码");
        frame.addSubComponent(passwordLabel);
        // build PasswordBox
        PasswordBox passwordBox = new PasswordBox("密码框");
        frame.addSubComponent(passwordBox);
        // build CheckBox
        CheckBox checkBox = new CheckBox("复选框");
        frame.addSubComponent(checkBox);
        // build remember username CheckBox
        TextBox rememberUsernameTextBox = new TextBox("记住用户名");
        frame.addSubComponent(rememberUsernameTextBox);
        // build forget password LinkLabel
        LinkLabel forgetPasswdLinkLabel = new LinkLabel("忘记密码");
        frame.addSubComponent(forgetPasswdLinkLabel);
        // display window
        winForm.display();
    }

    private static void buildWinFormWithBuilder() {
        // build WinForm
        WinForm winForm = new WinForm("WINDOW窗口");
        winForm
            .addSubComponent(new Picture("LOGO图片")) // build Picture
            .addSubComponent(new Button("登录"))      // build Login Button
            .addSubComponent(new Button("注册"));     // build Register Button
        // build Frame
        Frame frame = new Frame("FRAME1");
        winForm.addSubComponent(frame);
        frame
            .addSubComponent(new Label("用户名"))           // build username Label
            .addSubComponent(new TextBox("用户名文本框"))    // build username TextBox
            .addSubComponent(new Label("密码"))             // build password Label
            .addSubComponent(new PasswordBox("密码框"))     // build PasswordBox
            .addSubComponent(new CheckBox("复选框"))        // build CheckBox
            .addSubComponent(new TextBox("记住用户名"))      // build remember username CheckBox
            .addSubComponent(new LinkLabel("忘记密码"));     // build forget password LinkLabel
        // display window
        winForm.display();
    }
}

输出结果:

2:47:16 下午: Executing task 'App.main()'...

Task :compileJava Task :processResources UP-TO-DATE Task :classes

Task :App.main() print WinForm(WINDOW窗口) print Picture(LOGO图片) print Button(登录) print Button(注册) print Frame(FRAME1) print Label(用户名) print TextBox(用户名文本框) print Label(密码) print PasswordBox(密码框) print CheckBox(复选框) print TextBox(记住用户名) print LinkLabel(忘记密码)

BUILD SUCCESSFUL in 1s 3 actionable tasks: 2 executed, 1 up-to-date 2:47:17 下午: Task execution finished 'App.main()'.

rooobot commented 4 years ago

这个设计一直让我心里不舒服,尤其是重新思考了面向对象的设计原则之后,时不是就有忍不住想重构掉的冲动,现在终于受不了了,重构完了。

具体的代码如下:

public interface Component {

    /**
     * Gui component's name
     * @return name
     */
    String getName();

    /**
     * Display detail info
     */
    void display();

}
public abstract class AbstractComponent implements Component {

    protected String name;

    public AbstractComponent(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

AbstractComponent抽象类封装了控件的公共属性name和公共行为getName()方法以及display()方法,getName()方法的逻辑是公共的,而display()方法的逻辑是与具体的不同控件相关的,所以是抽象方法。

以下为各具体控件的代码:

public class Button extends AbstractComponent {

    public Button(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print Button(" + getName() + ")");
    }
}
public class CheckBox extends AbstractComponent {

    public CheckBox(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print CheckBox(" + getName() + ")");
    }
}
public class Frame extends AbstractComponent {

    private List<Component> subComponents = new ArrayList<>();

    public Frame(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print Frame(" + getName() + ")");
        for (Component sub : subComponents) {
            sub.display();
        }
    }

    public Frame addSubComponent(Component component) {
        this.subComponents.add(component);
        return this;
    }
}
public class Label extends AbstractComponent {

    public Label(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print Label(" + getName() + ")");
    }
}
public class LinkLabel extends AbstractComponent {

    public LinkLabel(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print LinkLabel(" + getName() + ")");
    }
}
public class PasswordBox extends AbstractComponent {

    public PasswordBox(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print PasswordBox(" + getName() + ")");
    }
}
public class Picture extends AbstractComponent {

    public Picture(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print Picture(" + getName() + ")");
    }
}
public class TextBox extends AbstractComponent {

    public TextBox(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print TextBox(" + getName() + ")");
    }
}
public class WinForm extends AbstractComponent {

    private List<Component> subComponents = new ArrayList<>();

    public WinForm(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("print WinForm(" + getName() + ")");
        for (Component sub : subComponents) {
            sub.display();
        }
    }

    public WinForm addSubComponent(Component component) {
        this.subComponents.add(component);
        return this;
    }
}

以上为具体的控件的代码,下面是main()方法:

public class App {

    public static void main(String[] args) {
        // build WinForm
        WinForm winForm = new WinForm("WINDOW窗口");
        winForm
            .addSubComponent(new Picture("LOGO图片")) // build Picture
            .addSubComponent(new Button("登录"))      // build Login Button
            .addSubComponent(new Button("注册"));     // build Register Button
        // build Frame
        Frame frame = new Frame("FRAME1");
        winForm.addSubComponent(frame);
        frame
            .addSubComponent(new Label("用户名"))           // build username Label
            .addSubComponent(new TextBox("用户名文本框"))    // build username TextBox
            .addSubComponent(new Label("密码"))             // build password Label
            .addSubComponent(new PasswordBox("密码框"))     // build PasswordBox
            .addSubComponent(new CheckBox("复选框"))        // build CheckBox
            .addSubComponent(new TextBox("记住用户名"))      // build remember username CheckBox
            .addSubComponent(new LinkLabel("忘记密码"));     // build forget password LinkLabel
        // display window
        winForm.display();
    }
}

运行后的输出如下:

3:10:26 下午: Executing task 'App.main()'...

> Task :compileJava
> Task :processResources UP-TO-DATE
> Task :classes

> Task :App.main()
print WinForm(WINDOW窗口)
print Picture(LOGO图片)
print Button(登录)
print Button(注册)
print Frame(FRAME1)
print Label(用户名)
print TextBox(用户名文本框)
print Label(密码)
print PasswordBox(密码框)
print CheckBox(复选框)
print TextBox(记住用户名)
print LinkLabel(忘记密码)

BUILD SUCCESSFUL in 1s
3 actionable tasks: 2 executed, 1 up-to-date
3:10:27 下午: Task execution finished 'App.main()'.

上面的示例,我们用AbstractComponent来封装了不同控件的公共行为和属性,分离出Component接口是因为对于FrameWinForm这种能容纳其它子控件的控件而言,它们关注的仅仅是子控件的行为,并不关注它们的具体实现,所以,通过Component接口将控件的行为单独分离出来,这样在FrameWinForm中就不用耦合AbstractComponent类,而只需要依赖于Component接口即可。(分离Component接口纯属我个人的思考)