设计模式-设计原则

目录

 

1、单一职责原则

2、开闭原则

 3、接口隔离原则

 4、依赖倒置原则

5、迪米特法则(最少知道原则)

6、里氏替换原则

7、组合优于继承


1、单一职责原则

每个方法、类、框架都只负责一件事情。
/**
 * 反例:
 * 统计一个文本文件中,有多少字符,所有功能在一个方法里
 */
public class Test {
    public static void main(String[] args) throws Exception {

        Reader in = new FileReader("d:\\a.txt");
        BufferedReader br = new BufferedReader(in);
        String line = null;
        StringBuilder sb = new StringBuilder("");
        while ((line = br.readLine()) != null) {
            sb.append(line)
                    .append("\n");
        }
        br.close();
        in.close();
        String[] words = sb.toString().split("[^a-zA-Z]+");
        System.out.println(words.length);

    }
}

以上代码,违反了单一职责,缺点:拓展功能时,代码重用性低,代码可读性低

// 读取txt文件
    private static String str(String path) throws Exception {
        Reader in = new FileReader(path);
        BufferedReader br = new BufferedReader(in);
        String line = null;
        StringBuilder sb = new StringBuilder("");
        while ((line = br.readLine()) != null) {
            sb.append(line)
                    .append("\n");
        }
        br.close();
        in.close();
        return sb.toString();
    }
    // 按特殊字符分割单词
    private static String[] getWords(String s) {
        String[] words = s.toString().split("[^a-zA-Z]+");
        return words;
    }
    public static void main(String[] args) throws Exception {
        String sb = str("d:\\a.txt");
        String[] words = getWords(sb);
        System.out.println(words.length);
    }

上述代码,符合单一职责

2、开闭原则

a、对扩展新功能开放
b、对修改原有功能关闭

 3、接口隔离原则

来自百度百科解释:

  • 客户端不应该依赖它不需要的接口
  • 类间的依赖关系应该建立在最小的接口上

 4、依赖倒置原则

程序要依赖于抽象接口,不要依赖于具体实现。

违反原则时:

class Person {
    public void feed(Dog dog) {
        System.out.println("开始喂狗。。。");
        dog.eat();
    }
}

class Dog {
    public void eat() {
        System.out.println("狗开始吃。。。");
    }
}

class Cat {
    public void eat() {
        System.out.println("猫开始吃。。。");
    }
}

// 当新增一个动物喂养时,无法满足
public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        Dog d = new Dog();
        p.feed(d);
        Cat c = new Cat();
        p.feed(c); // 报错,无法实现,需要修改
    }
}

满足原则:

class Person {
    public void feed(Animal animal) {
        System.out.println("开始喂。。。");
        animal.eat();
    }
}

interface Animal {
    void eat();
}

class Dog implements Animal {
    public void eat() {
        System.out.println("狗开始吃。。。");
    }
}

class Cat implements Animal {
    public void eat() {
        System.out.println("猫开始吃。。。");
    }
}

public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        Dog d = new Dog();
        p.feed(d);
        Cat c = new Cat();
        p.feed(c); 
    }
}

5、迪米特法则(最少知道原则)

迪米特法则,也叫最少知道原则(封装)
一个类,对于其他类,要知道的越浅越好
强调只和朋友说话,不和陌生人说话。
注:朋友指的是出现在成员变量、参数、返回值的类,而出现在方法体内部的类不属于

反例:

public class Test {
    public static void main(String[] args) {
        Foo f = new Foo();
        Bar bar = f.get();
        bar.t1();
    }
}
class Bar {
    public String t1(){
        return "";
    }
}
class Foo {
    public Bar get(){
        return new Bar();
    }
}

 

Foo是Test类的朋友,但Bar是Test类的陌生人。

6、里氏替换原则

任何能使用父类对象的地方,都应该能透明的替换为子类对象

1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法

2)子类中可以增加自己特有的方法。

3)当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

4)当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

举例说明:点击这里 

7、组合优于继承

 需求:制作一个集合,要求该集合能记录至今为止添加过多少个元素

public class Test {
    public static void main(String[] args) {
        MySet set = new MySet();
        Set set2 = new HashSet();
        set2.add("测试");
        set2.add("集合");
        set2.add("添加");
        set.addAll(set2);
        System.out.println(set.getCount());
    }
}
class MySet extends HashSet {
    private int count = 0;
    public boolean add(Object o) {
        count++;
        return super.add(o);
    }
    public boolean addAll(Collection c) {
        count += c.size();
        return super.addAll(c);
    }
    public int getCount() {
        return count;
    }
}

存在问题:addAll会回调add方法,导致统计个数不对。

    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

由问题分析可知,父类HashSet addAll调用了add,所以将子类的addAll重写去除,好像这样就可以实现该功能。但这样真的可行吗?

注:如若HashSet addAll不再调用add时,将会导致该子类再一次错误。

 那这里进一步修改addAll,让其不再调用父类的:

public boolean addAll(Collection c) {
        boolean flag = false;
        for(Object o : c) {
            if(add(o)) {
                flag = true;
            }
        }
        return flag;
    }

这种方式可以解决父类addAll方法被修改的问题,但是一旦父类新增了一个add相关的方法,这时由于子类MySet没有对其修改就会导致无法实现统计已添加元素的个数。

 由上分析,这里的MySet不再去继承HashSet了,而是让MySet和HashSet发生关联关系:

class MySet {
    private int count = 0;
    private Set set = new HashSet();
    public boolean add(Object o) {
        count++;
        return set.add(o);
    }
    public boolean addAll(Collection c) {
        count += c.size();
        return set.addAll(c);
    }
    public int getCount() {
        return count;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值