[译] 如何”优雅”的用设计模式来写一个Hello World.

Transtaled from The Abuse of Design Patterns in writing a Hello World Program with authorization.

转载+翻译已获取原作者(Taskinoor Hasan)授权, 二次转载请注明出处(https://snowstar.org/2018/06/22/the-abuse-of-design-patterns-in-writing-a-hello-world-program/)

“One comment I saw in a news group just after patterns started to become more popular was someone claiming that in a particular program they tried to use all 23 GoF patterns. They said they had failed, because they were only able to use 20. They hoped the client would call them again to come back again so maybe they could squeeze in the other 3.

Trying to use all the patterns is a bad thing, because you will end up with synthetic designs—speculative designs that have flexibility that no one needs. These days software is too complex. We can’t afford to speculate what else it should do. We need to really focus on what it needs.” – Erich Gamma [1]

当人们开始学习设计模式的时候, 他们总是想把设计模式用到任何地方. 不管是否需要设计模式, 人们总是试图在任何地方使用设计模式. 他们认为用的设计模式越多, 就是越好的设计. 这所带来的后果就是增加了代码的不必要的复杂度.

这并不是叫做"使用设计模式", 而是叫做"滥用设计模式". 接下来将会讲一个滥用设计模式来实现 Hello World 程序的例子.

我们来看一下这个例子. 这是一个经典的问题: 写出一个在标准输出上打印 Hello World 的程序

初学者可能会这样写代码(Java):

System.out.println("hello world");

这段代码非常简单. 如果我们加入一些设计模式进去会怎么样? 让我们试试看...

首先我们定义两个接口 SubjectObserver 来实现观察者模式(Observer).

public interface Subject {
    public void attach(Observer observer);
    public void detach(Observer observer);
    public void notifyObservers();
}

public interface Observer {
    public void update(Subject subject);
}

紧接着我们定义两个类 HelloWorldSubjectHelloWorldObserver 来实现他们.

public class HelloWorldSubject implements Subject {

    private ArrayList<Observer> observers;
    private String str;

    public HelloWorldSubject() {
        super();

        observers = new ArrayList<Observer>();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void detach(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers() {
        Iterator<Observer> iter = observers.iterator();

        while (iter.hasNext()) {
            Observer observer = iter.next();
            observer.update(this);
        }
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
        notifyObservers();
    }
}

public class HelloWorldObserver implements Observer {

    public void update(Subject subject) {
        HelloWorldSubject sub = (HelloWorldSubject)subject;
        System.out.println(sub.getStr());
    }

}

然后我们添加一个 Command.

public interface Command {
    void execute();
}

public class HelloWorldCommand implements Command {

    private HelloWorldSubject subject;

    public HelloWorldCommand(Subject subject) {
        super();

        this.subject = (HelloWorldSubject)subject;
    }

    public void execute() {
        subject.setStr("hello world");
    }

}

再添加一个 抽象工厂模式(Abstract Factory).

public interface AbstractFactory {
    public Subject createSubject();
    public Observer createObserver();
    public Command createCommand(Subject subject);
}

public class HelloWorldFactory implements AbstractFactory {

    public Subject createSubject() {
        return new HelloWorldSubject();
    }

    public Observer createObserver() {
        return new HelloWorldObserver(); 
    }

    public Command createCommand(Subject subject) {
        return new HelloWorldCommand(subject);
    }
}

最后我们添加一个 单例模式(Singleton).

public class FactoryMakerSingleton {

    private static FactoryMakerSingleton instance = null;
    private AbstractFactory factory;

    private FactoryMakerSingleton() {
        factory = new HelloWorldFactory();
    }

    public static synchronized FactoryMakerSingleton getInstance() {
        if (instance == null) {
            instance = new FactoryMakerSingleton();
        }

        return instance;
    }

    public AbstractFactory getFactory() {
        return factory;
    }
}

当然最主要的 main 放在最后.

public class AbuseDesignPatterns {

    public static void main(String[] args) {
        AbstractFactory factory = FactoryMakerSingleton.getInstance().getFactory();

        Subject subject = factory.createSubject();
        subject.attach(factory.createObserver());

        Command command = factory.createCommand(subject);

        command.execute();
    }

}

当这么多代码跑起来之后, 最终输出结果就是 Hello World.

哇, 我们成功的在 Hello World 程序中用到了设计模式! (好吧, 其实还有个 迭代器模式(Iterator), 不过我们用了Java内建的迭代器, 这在Java当中是再自然不过的事情了.) 这一定是一个很好的设计. 那么问题出在了哪里呢?

  1. 这对于一个Hello World程序来说太复杂了(:з)∠)
  2. 它包含了我们从来都不会用到的灵活性.
  3. 设计这些模式和实现他们简直是太浪费时间了!
  4. 这将会使我们的代码膨胀很多.
  5. 这违背了 KISS 原则. [3] (译者注, Keep it simple, stupid, 也是我非常喜欢的一句名言)
  6. 这已经不是在解决问题了. 我们的目标是学习如何在标准输出中打印, 但这代码已经严重偏离目标了.

总结: 合理的使用设计模式, 不要想着到处都用. 对于设计一个好的软件来说, 设计模式是一个强有力的工具. 明智的使用设计模式, 而不要滥用.

代码可以从这里下载到. 欢迎任何反馈. 当然如果有人能在 Hello World 程序里面用到更多的设计模式那就再好不过了.
(译者注: 代码下载链接在 dropbox, 国内需科学, 若需联系原作者, 可从本文顶部进入原文章.)

引用:
[1] How to Use Design Patterns..
[2] Chapter 13: Patterns in the Real World from Head First Design Patterns.
[3] KISS Principle.

发表评论

电子邮件地址不会被公开。 必填项已用*标注