共计 6642 个字符,预计需要花费 17 分钟才能阅读完成。
写在后面
- 记录学习设计模式的笔记
- 进步对设计模式的灵活运用
学习地址
https://www.bilibili.com/vide…
https://www.bilibili.com/vide…
参考文章
http://c.biancheng.net/view/1…
我的项目源码
https://gitee.com/zhuang-kang/DesignPattern
3,软件设计准则
在软件开发中,为了进步软件系统的可维护性和可复用性,减少软件的可扩展性和灵活性,程序员要尽量依据 6 条准则来开发程序,从而进步软件开发效率、节约软件开发老本和保护老本。
3.1 开闭准则
对扩大凋谢,对批改敞开 。在程序须要进行拓展的时候,不能去批改原有的代码,实现一个热插拔的成果。简言之,是为了使程序的扩展性好,易于保护和降级。
想要达到这样的成果,咱们须要应用接口和抽象类。
因为形象灵活性好,适应性广,只有形象的正当,能够根本放弃软件架构的稳固。而软件中易变的细节能够从抽象派生来的实现类来进行扩大,当软件须要发生变化时,只须要依据需要从新派生一个实现类来扩大就能够了。
3.2 里氏代换准则
里氏代换准则是面向对象设计的根本准则之一。
里氏代换准则:任何基类能够呈现的中央,子类肯定能够呈现。艰深了解:子类能够扩大父类的性能,但不能扭转父类原有的性能。换句话说,子类继承父类时,除增加新的办法实现新增性能外,尽量不要重写父类的办法。
如果通过重写父类的办法来实现新的性能,这样写起来尽管简略,然而整个继承体系的可复用性会比拟差,特地是使用多态比拟频繁时,程序运行出错的概率会十分大。
里氏代换准则谬误示范
package com.zhuang.principle.liskov;
/**
* @Classname Liskov
* @Description 里氏代换准则谬误示范
* @Date 2021/3/15 13:58
* @Created by dell
*/
public class Liskov {public static void main(String[] args) {A a = new A();
System.out.println("11-3=" +a.fun1(11,3));
System.out.println("11-8=" +a.fun1(11,8));
System.out.println("===================");
B b = new B();
System.out.println("11-3="+b.fun1(11,3));
System.out.println("1-8="+b.fun1(1,8));
System.out.println("11+3+9="+b.fun2(11,3));
}
}
class A{
// 返回两个数的差
public int fun1(int num1,int num2){return num1-num2;}
}
// B 类继承 A 减少新性能,实现两个数相加,而后和 9 求和
class B extends A{
@Override
public int fun1(int a, int b) {return a+b;}
public int fun2(int a, int b) {return fun1(a,b)+9;
}
}
里氏代换准则正确示范
package com.zhuang.principle.liskov;
/**
* @Classname Liskov2
* @Description 里氏代换准则
* @Date 2021/3/15 14:13
* @Created by dell
*/
public class Liskov2 {public static void main(String[] args) {Base base = new Base();
base.add(5,6);
base.sub(6,2);
Sub sub = new Sub();
sub.mul(5,6);
sub.div(10,2);
}
}
class Base {
// 通用加法运算
public void add(int a, int b) {System.out.println(a + "+" + b + "=" + (a + b));
}
// 通用减法运算
public void sub(int a, int b) {System.out.println(a + "-" + b + "=" + (a - b));
}
}
class Sub extends Base {
// 子类特有乘法运算
public void mul(int a, int b) {System.out.println(a + "*" + b + "=" + (a * b));
}
// 子类特有除法运算
public void div(int a, int b) {System.out.println(a + "/" + b + "=" + (a / b));
}
}
3.3 依赖倒转准则
高层模块不应该依赖低层模块,两者都应该依赖其形象;形象不应该依赖细节,细节应该依赖形象。简略的说就是要求对形象进行编程,不要对实现进行编程,这样就升高了客户与实现模块间的耦合。
依赖倒转准则谬误示范
package com.zhuang.principle.inversion;
/**
* @Classname DependenceInversion1
* @Description 依赖倒转准则谬误示范
* @Date 2021/3/15 13:20
* @Created by dell
*/
public class DependenceInversion1 {public static void main(String[] args) {Person person = new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
// 定义接口
interface IReceiver{public String getInfo();
}
class WeiXin implements IReceiver{
@Override
public String getInfo() {return "发送微信音讯...";}
}
class Email implements IReceiver{
@Override
public String getInfo() {return "发送邮件音讯...";}
}
// 对接口的依赖
class Person{public void receive(IReceiver receiver){System.out.println(receiver.getInfo());
}
}
依赖倒转准则正确示范
package com.zhuang.principle.inversion;
/**
* @Classname DependenceInversion2
* @Description 依赖倒转准则正确示范
* @Date 2021/3/15 13:27
* @Created by dell
*/
public class DependenceInversion2 {public static void main(String[] args) {Client client = new Client();
client.receive(new Emailiml());
client.receive(new WXimpl());
}
}
interface IReceive{public void printInfo(Integer uid);
}
class WXimpl implements IReceive {
@Override
public void printInfo(Integer uid) {System.out.println("发送微信音讯"+uid);
}
}
class Emailiml implements IReceive {
@Override
public void printInfo(Integer uid) {System.out.println("发送邮件信息"+uid);
}
}
class Client{public void receive(IReceive receive){receive.printInfo(12345);
}
}
面向对象的开发很好的解决了这个问题,个别状况下形象的变动概率很小,让用户程序依赖于形象,实现的细节也依赖于形象。即便实现细节一直变动,只有形象不变,客户程序就不须要变动。这大大降低了客户程序与实现细节的耦合度。
3.4 接口隔离准则
客户端不应该被迫依赖于它不应用的办法;一个类对另一个类的依赖应该建设在最小的接口上。
接口隔离准则
package com.zhuang.principle.segregation;
/**
* @Classname Sergregation
* @Description 接口隔离准则
* @Date 2021/3/15 13:02
* @Created by dell
*/
public class Sergregation {public static void main(String[] args) {C c = new C();
c.depend1(new A());
c.depend2(new A());// C 类通过接口去依赖 A 类
c.depend3(new A());
System.out.println("=======================");
D d = new D();
d.depend1(new B());
d.depend4(new B());// D 类通过接口去依赖 B 类
d.depend5(new B());
}
}
interface interface1{void operation1();
}
interface interface2{void operation2();
void operation3();}
interface interface3{void operation4();
void operation5();}
class A implements interface1,interface2{
@Override
public void operation1() {System.out.println("A 实现了 operation1.....");
}
@Override
public void operation2() {System.out.println("A 实现了 operation2......");
}
@Override
public void operation3() {System.out.println("A 实现了 operation3......");
}
}
class B implements interface1,interface3{
@Override
public void operation1() {System.out.println("B 实现了 operation1.....");
}
@Override
public void operation4() {System.out.println("B 实现了 operation4.....");
}
@Override
public void operation5() {System.out.println("B 实现了 operation5.....");
}
}
// C 类通过接口 interface1,interface2 依赖应用 A 类 只会应用到 1,2,3 办法
class C{public void depend1(interface1 i){i.operation1();
}
public void depend2(interface2 i){i.operation2();
}
public void depend3(interface2 i){i.operation3();
}
}
// D 类通过接口 interface1,interface3 依赖应用 B 类,用到 1,4,5 办法
class D{public void depend1(interface1 i){i.operation1();
}
public void depend4(interface3 i){i.operation4();
}
public void depend5(interface3 i){i.operation5();
}
}
3.5 迪米特法令
迪米特法令又叫起码常识准则。
只和你的间接敌人交谈,不跟“陌生人”谈话(Talk only to your immediate friends and not to strangers)。
其含意是:如果两个软件实体毋庸间接通信,那么就不该当产生间接的互相调用,能够通过第三方转发该调用。其目标是升高类之间的耦合度,进步模块的绝对独立性。
迪米特法令中的“敌人”是指:以后对象自身、以后对象的成员对象、以后对象所创立的对象、以后对象的办法参数等,这些对象同以后对象存在关联、聚合或组合关系,能够间接拜访这些对象的办法。
上面看一个例子来了解迪米特法令
【例】明星与经纪人的关系实例
明星因为全身心投入艺术,所以许多日常事务由经纪人负责解决,如和粉丝的见面会,和媒体公司的业务洽淡等。这里的经纪人是明星的敌人,而粉丝和媒体公司是陌生人,所以适宜应用迪米特法令。
类图如下:
代码如下:
明星类(Star)
public class Star {
private String name;
public Star(String name) {this.name=name;}
public String getName() {return name;}
}
粉丝类(Fans)
public class Fans {
private String name;
public Fans(String name) {this.name=name;}
public String getName() {return name;}
}
媒体公司类(Company)
public class Company {
private String name;
public Company(String name) {this.name=name;}
public String getName() {return name;}
}
经纪人类(Agent)
public class Agent {
private Star star;
private Fans fans;
private Company company;
public void setStar(Star star) {this.star = star;}
public void setFans(Fans fans) {this.fans = fans;}
public void setCompany(Company company) {this.company = company;}
public void meeting() {System.out.println(fans.getName() + "与明星" + star.getName() + "见面了。");
}
public void business() {System.out.println(company.getName() + "与明星" + star.getName() + "洽淡业务。");
}
}
3.6 合成复用准则
合成复用准则是指:尽量先应用组合或者聚合等关联关系来实现,其次才思考应用继承关系来实现。
通常类的复用分为继承复用和合成复用两种。
继承复用尽管有简略和易实现的长处,但它也存在以下毛病:
- 继承复用毁坏了类的封装性。因为继承会将父类的实现细节裸露给子类,父类对子类是通明的,所以这种复用又称为“白箱”复用。
- 子类与父类的耦合度高。父类的实现的任何扭转都会导致子类的实现发生变化,这不利于类的扩大与保护。
- 它限度了复用的灵活性。从父类继承而来的实现是动态的,在编译时曾经定义,所以在运行时不可能发生变化。
采纳组合或聚合复用时,能够将已有对象纳入新对象中,使之成为新对象的一部分,新对象能够调用已有对象的性能,它有以下长处:
- 它维持了类的封装性。因为成分对象的外部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
- 对象间的耦合度低。能够在类的成员地位申明形象。
- 复用的灵活性高。这种复用能够在运行时动静进行,新对象能够动静地援用与成分对象类型雷同的对象。
上面看一个例子来了解合成复用准则
【例】汽车分类管理程序
汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“色彩”划分可分为红色汽车、彩色汽车和红色汽车等。如果同时思考这两种分类,其组合就很多。类图如下:
从下面类图咱们能够看到应用继承复用产生了很多子类,如果当初又有新的动力源或者新的色彩的话,就须要再定义新的类。咱们试着将继承复用改为聚合复用看一下。
写在最初
- 如果我的文章对你有用,请给我点个👍,感激你😊!
- 有问题,欢送在评论区指出!💪