让“上帝的归上帝,凯撒的归凯撒”

 

近日在研习由Trygve Reenskaug(著名的mvc架构提出者)发表的论文"The DCI Architecture - A New Vision of OOP",其中提出的框架模式就叫DCI架构。由数据、场景、交互组成。我理解,这是一种用例驱动设计的OO编程范式式。原作中似乎希望对象在运行时执行相应的逻辑来完成不同的场景用例。关于这一点我还没有理解透彻,期间我想过使用AOP为对象切入逻辑,但感觉太笨重;基于多继承的minin技术,好像也不太适合java语言;用java8函数式编程lambda表达式,比如实现Consumer接口然后方法引用,但也不是动态性的……百思不得其解。暂时搁置这个问题。不过DCI提出的理念很好,它追求让编程更符合用户的心智模型,我也仿照其基本的结构雏形写了些demo,确实感觉很清晰。比如一个用户开车的用例。上代码:

package com.xfkj.themeE;

/**
 * 汽车类
 */
public class Car {
    private int id;
    private String name;//名字
    private String brand;//品牌

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void run(){
        System.out.println("作为一个汽车,我肯定能跑");
    }
}


package com.xfkj.themeE;

/**
 * 人类
 */

public class Person{
    private String name;//姓名
    private int age;//年龄

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat(String food){
        System.out.println("作为一个人我得吃东西,例如:"+food);
    }




}


package com.xfkj.themeE;

/**
 * 司机角色接口
 */
public interface IDriverRole {
    void driveCar(Car car);
    void maintenceCar(Car car);

}


public class Driver extends Person implements IDriverRole{
    private Person p;
    private int driveAge;

    public int getDriveAge() {
        return driveAge;
    }

    public void setDriveAge(int driveAge) {
        this.driveAge = driveAge;
    }

    public Driver(){
        super();
    }
    public Driver(Person p) {
        this.p = p;
    }

    public Person getP() {
        return p;
    }

    public Driver setP(Person p) {
        this.p = p;
        return this;
    }

    @Override
    public void driveCar(Car car) {
        System.out.println("呦吼!开着我的"+car.getBrand()+"座驾去兜风喽!");
    }

    @Override
    public void maintenceCar(Car car) {
        System.out.println("作为一名合格的司机,对于爱驾"+car.getName()+"日常维护还是要的!");

    }
}



package com.xfkj.themeE;

/**
 * 开车场景(上下文)
 */
public class DriverCarCtx {
    public static void main(String[] args) {
        Car car=new Car();
        car.setName("汗血宝马");
        car.setBrand("BMW");
        car.run();

        Person person=new Person();
        person.setName("gmh");
        person.setAge(32);
        person.eat("米饭");
        IDriverRole iDriverRole=new Driver(person);
        System.out.println(((Driver) iDriverRole).getP().getName()+"学会了开车,摇身一变成了司机!");

        iDriverRole.driveCar(car);
        iDriverRole.maintenceCar(car);


    }
}

关于如何实现动态交互,无外乎是将有状态的对象转移给接口实现,或者将方法逻辑注入给对象,也就是method(obj)或者obj.method()的问题,以上的代码并没有真正实现DCI架构。只是受到其启发,作为一种实践探索。

关于角色实现类,也就是司机究竟是继承人类还是组成人类,我有一些理解。以下是我写在上面代码demo里的注释,直接copy过来。

司机这个角色是什么?司机由什么组成(有什么),这是继承和组合区别的核心问题
* 为什么优先用组合而不是继承?完成一项任务,只需要考虑由哪些构件去组合(尽管构件重要程度也有主次),
* 只要能把活干了,就行;在需要更换实现时,换掉构件即可;而继承是一脉相成的,它“是”它的父类;
* 当父类有些不属性和方法是子类不需要的时,也只能冗余的继承过来;如果需要修改实现,就需要修改父类,
* 问题是父类不止有一个子类,这会影响其他子类实现。这是强耦合。至于持久化问题,也无需担心,继承关系有继承映射,
* 组成关系有OneToOne、OneToMany等进行外键关联。从本例的实际意义来看,司机这个角色不一定是
* 人来扮演,也可能是训练有素的大猩猩或机器人;但人这个对象进入了开车这个场景,他确实是个司机;
* 并且人这个对象也能进入不同场景去扮演不同的角色。DCI要解决的问题就是把对象具有稳定性的属性和行为
* 与不稳定的因素分开,这暗含了稳定的对象是需要复用的含义,无论是当即在应用中多处依赖,还是在以后
* 的扩展维护中让他扮演其他角色。DCI架构可以类比一个剧本。某个场景由一些演员和其他道具组成,
* 本例中人类扮演了一个司机角色,道具对象是车子,交互行为是开车,场景上下文对象就起到了打板(触发交互)
* 和演出场地(协调调度对象),整个剧情过程就是算法。而一个剧本是由多场戏镜头拼接而成的,这就像
* 一个应用是由多个用例组成的一样。编程,是一种抽象活动;既然是抽象活动,它所有的类和对象其实都是概念层次的
* ,是形而上的,千万不要固执的用有形的、可观测的事物去映射。例如,我们想当然的认为开车时由人来开;其实不是,
* 车应该是由司机来开,尽管司机这个角色在现实生活中,需要一些载体;但在编程这种抽象模型中,它不需要。
* 无人驾驶技术越来越有眉目了,这不难理解。再比如“变速箱”这个类,“挂挡”这个方法应该放在哪里?你可能说就放在
* 变速箱本类中,毕竟把方法放在合适的类中这是程序员的职责。但细细研究,其实不合理。挂挡是一个行为,而其真正
* 产生的效果是“变速”,“变速箱”这个类中,应该有的是变速方法;那有人会说,放在“人”类里,也不对。人能干的事太多了,
* 那人类会变成上帝类,万能类(大泥球);按照上述的DCI架构,挂挡是司机干的活,你别管司机是谁来扮演。大金毛训练有素
* 也能挂挡。让“上帝的归上帝,凯撒的归凯撒”。*/

你可能感兴趣的:(设计模式)