设计模式原则笔记

设计模式原则笔记


  • 合成复用原则
合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。通常类的复用分为继承复用和合成复用。
继承复用虽然简单和易实现的有点,但是它也存在以下的缺点:
1.继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为'白箱'复用。
2.子类与父类的耦合度高。父类实现的任何改变导致子类的实现发生改变就,这不利于类的扩展和维护。
3.它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。
组合或聚合复用,可以将原始对象添加为新对象的一部分,使得新对象可以调用原始对象的功能,它具有以下的优点:
1.它维持了类的封装性。因为成员对象内部细节是新对象看不见的,所以这种复用又被称之为'黑箱'复用。
2.对象间的耦合度低。定义成员属性时,可以在成员位置声明为抽象。
3.复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用成员对象类型相同的对象。

如下UML类图中可以看出用继承关系实现会产生很多子类,而且增加新的宠物或者增加新的颜色都要修改源代码,这违背了开闭原则,显然不可取。但如果改用组合关系实现就能很好地解决以上问题:

«abstract» Pet +String name +int age +eat(String food) : void Cat +eat(String food) : void Dog +eat(String food) : void GrayCat -String COLOR +talk() : void BlackCat -String COLOR +talk() : void BlackDog -String COLOR +talk() : void GrayDog -String COLOR +talk() : void
// Pet.java
package com.wu.DesignPattern;

public abstract class Pet {
    public String name;
    public int age;
    public abstract void eat(String food);
}
// Cat.java
package com.wu.DesignPattern;

public class Cat extends Pet{
    public Cat(String name,int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public void eat(String food) {
        System.out.println("小猫"+this.name+"正在吃"+food);
    }
}
// BlackCat.java
package com.wu.DesignPattern;

public class BlackCat extends Cat{
    private final String COLOR = "Black";
    public BlackCat(String name, int age) {
        super(name, age);
    }
    public void talk(){
        System.out.println("我是一只小黑猫… ");
    }
}

改进后:

«abstract» Pet +String name +int age #Color color +eat(String food) : void +Pet(Color color) Cat +eat(String food) : void +talk() : void Dog +eat(String food) : void +talk() : void «abstract» Color GrayColor +String COLOR BlackColor +String COLOR
// Pet.java
package com.wu.DesignPattern;

public abstract class Pet {
    public String name;
    public int age;
    Color color;
    public abstract void eat(String food);
}
// Cat.java
package com.wu.DesignPattern;

public class Cat extends Pet{
    public Cat(String name,int age,Color color){
        this.name = name;
        this.age = age;
        this.color = color;
    }
    @Override
    public void eat(String food) {
        System.out.println("小猫"+this.name+"正在吃"+food);
    }
    public void talk(){
        System.out.println("我是一只"+this.color+"猫");
    }
}
// Color.java
package com.wu.DesignPattern;

public abstract class Color {}
// BlackColor.java
package com.wu.DesignPattern;

public class BlackColorextends Color{
    public static final String COLOR = "Black";
}
// Client.java
package com.wu.DesignPattern;

public class Client {
    public static void main(String[] args) {
        Color color = new BlackColor();
        Pet pet = new Cat("小黑",4,color);
        pet.eat("早餐");
    }
}
  • 接口隔离原则
接口隔离原则是指:客户端不应该被迫依赖于他不会使用的方法,一个类对另一类的依赖应该建立在最小的接口上,即应该将胖接口中的方法分组,然后用多个接口替代它,每个接口服务于一个子模块。简单地说,就是使用多个专门的接口比使用单个接口要好很多。

如下,对于每一扇门都会实现所有接口:

«interface» Door +theftProof() : void +waterProof() : void +fireProof() : void MyDoor1 MyDoor2

改进后:

«interface» TheftProof +theftProof() : void «interface» WaterProof +waterProof() : void «interface» FireProof +fireProof() : void MyDoor1 MyDoor2
  • 开闭原则
开闭原则是指:对扩展开放,对修改关闭。在程序需要进行拓展时候,不能修改原有的代码,实现一个热插拔的效果。简而言之,是为了使程序的扩展性好,易于维护和升级。
想要达到这样的效果,我们需要使用接口和抽象类。因为抽象类灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构稳定。而软件中易变得细节可以从抽象派生来实现类进行扩展,当软件需要发生改变时,只需要根据需求重新派生一个实现类来扩展即可。
  • 里氏代换原则
里氏代换原则是指:任何基类可以出现的地方,子类一定可以出现。通俗的说就是,子类可以扩展父类的功能,但不能改变父类原有的功能,也就是说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
如果通过重写父类的方法来完成新的功能,这样虽然看起来简单了,但是整个继承体系的可复用性会变得比较差,特别是运用多态比较频繁时,程序出错的概率会非常大。
  • 依赖倒转原则
依赖倒转原则是指:高层模块不应该依赖低层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。简单地说,就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户端与实现模块之间的耦合。
  • 迪米特原则
迪米特原则是指:当两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是为了降低类之间的耦合度,提高模块之间的相对独立性。
这里可以直接通信的实体一般为:当前对象本身、当前对象的成员对象、当前所创建的对象、当前对象的方法参数等,这些对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。


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