关于Java中软件设计原则

关于Java中软件设计原则,第1张

关于Java中软件设计原则
    • 1 开闭原则
      • 1 案例
        • 1 抽象皮肤类
        • 2 默认皮肤类
        • 3 自定义皮肤类
        • 4 搜狗拼音类
        • 5 测试类
        • 6 结果
    • 2 里氏替换原则
      • 1 案例
        • 1 长方形类
        • 2 正方形类
        • 3 测试类
        • 4 结果
      • 2 案列改造
        • 1 创建四方形接口
        • 2 创建长方形类
        • 3 正方形类
        • 4 测试类
        • 5 结果
    • 3 依赖倒转原则
      • 1 案例
        • 1 电脑类
        • 2 希捷硬盘类
        • 3 Intel处理器类
        • 4 金士顿内存条类
        • 5 测试类
        • 6 运行结果
      • 2 案例改造
        • 1 电脑类
        • 2 希捷硬盘类
        • 3 AMD处理器类
        • 4 金士顿内存条
        • 5 测试类
        • 6 结果
    • 4 接口隔离原则
      • 1 案例
        • 1 安全门接口
        • 2 小牛牌
      • 2 案例改造
        • 1 防盗接口
        • 2 防火接口
        • 3 防水接口
        • 4 小狗牌
    • 5 迪米特法则
      • 1 案例
        • 1 明星类
        • 2 粉丝类
        • 3 广告公司类
        • 4 经纪人类
    • 6 合成复用原则
      • 1 案例
        • 1 按照继承关系来划分
          • 1 汽车类
          • 2 油车
          • 3 红色油车
          • 4 白色油车
          • 5 电车
          • 6 红色电车
          • 7 白色电车
        • 2 按照聚合复用关系来划分
          • 1 颜色接口
          • 2 汽车类

对于Java中常用的设计模式, 规定了其设计原则,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,我们要尽量根据6条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本

1 开闭原则

对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果.

因为抽象灵活性好, 我们以接口和抽象类实现案例效果.

1 案例

以搜狗输入法的皮肤替换为例, 搜狗输入法有默认的皮肤,也能用户自定义皮肤.首先需要定义一个皮肤抽象类,让二者继承.

1 抽象皮肤类
public abstract class AbstractSkin {
    public abstract void display();
}
2 默认皮肤类
public class DefaultSkin extends AbstractSkin {
    @Override
    public void display() {
        System.out.println("默认皮肤");
    }
}
3 自定义皮肤类
public class CustomSkin extends AbstractSkin {
    @Override
    public void display() {
        System.out.println("自定义皮肤");
    }
}
4 搜狗拼音类
public class SougouInput {

    private AbstractSkin skin;

    public void setSkin(AbstractSkin skin) {
        this.skin = skin;
    }

    public void display() {
        skin.display();
    }
}
5 测试类
public class Client {
    public static void main(String[] args) {
        // 1 创建输入法对象
        SougouInput sougouInput = new SougouInput();
        // 2 创建皮肤对象
//        DefaultSkin skin = new DefaultSkin();
        CustomSkin skin = new CustomSkin();

        // 3 设计默认皮肤
        sougouInput.setSkin(skin);

        // 4 查看皮肤
        sougouInput.display();
    }
}
6 结果
// 第一次 默认皮肤
// 第二次 自定义皮肤

通过接口和抽象类,实现了搜狗拼音的皮肤切换,当后续出现其他皮肤类型,只需要创建一个实现类即可

2 里氏替换原则

里氏代换原则:任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能.

1 案例

以正方形和长方形为例, 因为正方形属于特殊的长方形. 所以首先创建一个长方形类,再创建一个正方形类继承长方形类.

1 长方形类
public class Rectangle {

    private double length;
    private double width;

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }
}
2 正方形类
public class Square extends Rectangle {
    @Override
    public void setLength(double length) {
        super.setLength(length);
        super.setWidth(length);

    }

    @Override
    public void setWidth(double width) {
        super.setWidth(width);
        super.setLength(width);
    }
}
3 测试类
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        // 设置长高
        rectangle.setLength(20);
        rectangle.setWidth(10);
        printLengthAndWidth(rectangle);
        System.out.println("-------------");

        Square square = new Square();
        square.setLength(10);
        resize(square);
        printLengthAndWidth(square);
    }

    public static void resize(Rectangle rectangle) {
        while (rectangle.getLength() <= rectangle.getWidth()) {
            rectangle.setWidth(rectangle.getWidth() + 1);
        }
    }

    public static void printLengthAndWidth(Rectangle rectangle) {
        System.out.println(rectangle.getLength());
        System.out.println(rectangle.getWidth());
    }

}
4 结果
20.0
10.0
-------------
程序一直再循环运行 正方形的长和宽一直再增加...
2 案列改造 1 创建四方形接口
public interface Quadrilateral {

    double getLength();

    double getWidth();
}
2 创建长方形类
public class Rectangle implements Quadrilateral {
    
    private double length;
    private double width;

    @Override
    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    @Override
    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }
}
3 正方形类
public class Square implements Quadrilateral {

    private double side;

    public void setSide(double side) {
        this.side = side;
    }

    public void setLength(double length) {
        side = length;
    }

    @Override
    public double getLength() {
        return side;
    }
    @Override
    public double getWidth() {
        return side;
    }
4 测试类
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        // 设置长高
        rectangle.setLength(20);
        rectangle.setWidth(10);
        printLengthAndWidth(rectangle);
        System.out.println("-------------");

        Square square = new Square();
        square.setLength(10);
        printLengthAndWidth(square);

        // 不能传递正方形到热size方法
    }

    public static void resize(Rectangle rectangle) {
        while (rectangle.getLength() <= rectangle.getWidth()) {
            rectangle.setWidth(rectangle.getWidth() + 1);
        }
    }

    public static void printLengthAndWidth(Quadrilateral quadrilateral) {
        System.out.println(quadrilateral.getLength());
        System.out.println(quadrilateral.getWidth());
    }

}
5 结果
20.0
10.0
-------------
10.0
10.0
3 依赖倒转原则

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象.

1 案例

以电脑类为例. 一个电脑需要基本的cpu,硬盘,内存条.

1 电脑类
public class Computer {

    private XiJieHardDisk hardDisk;
    private IntelCpu cpu;
    private KingstonMemory memory;

    public IntelCpu getCpu() {
        return cpu;
    }

    public void setCpu(IntelCpu cpu) {
        this.cpu = cpu;
    }

    public KingstonMemory getMemory() {
        return memory;
    }

    public void setMemory(KingstonMemory memory) {
        this.memory = memory;
    }

    public XiJieHardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(XiJieHardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public void run() {
        System.out.println("计算机工作");
        cpu.run();
        memory.save();
        String data = hardDisk.get();
        System.out.println("从硬盘中获取的数据为:" + data);
    }
}
2 希捷硬盘类
public class XiJieHardDisk {

    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据" + data);
    }

    public String get() {
        System.out.println("使用希捷希捷硬盘取数据");
        return "数据";
    }
}
3 Intel处理器类
public class IntelCpu {

    public void run() {
        System.out.println("使用Intel处理器");
    }
}
4 金士顿内存条类
public class KingstonMemory {

    public void save() {
        System.out.println("使用金士顿作为内存条");
    }
}
5 测试类
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.setHardDisk(new XiJieHardDisk());
        computer.setCpu(new IntelCpu());
        computer.setMemory(new KingstonMemory());

        computer.run();
    }
}
6 运行结果
计算机工作
使用Intel处理器
使用金士顿作为内存条
使用希捷希捷硬盘取数据
从硬盘中获取的数据为:数据

上述电脑,相关配件已经固定,如果想要换成AMD的cpu或其他品牌的内存条等就不行了.

2 案例改造 1 电脑类
public class Computer {

    private HardDisk hardDisk;
    private Cpu cpu;
    private Memory memory;

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public Memory getMemory() {
        return memory;
    }

    public void setMemory(Memory memory) {
        this.memory = memory;
    }

    public HardDisk getHardDisk() {
        return hardDisk;
    }

    public void setHardDisk(HardDisk hardDisk) {
        this.hardDisk = hardDisk;
    }

    public void run() {
        System.out.println("计算机工作");
        cpu.run();
        memory.save();
        String data = hardDisk.get();
        System.out.println("从硬盘中获取的数据为:" + data);
    }
}
2 希捷硬盘类
public class XiJieHardDisk implements HardDisk {

    public void save(String data) {
        System.out.println("使用希捷硬盘存储数据" + data);
    }

    public String get() {
        System.out.println("使用希捷希捷硬盘取数据");
        return "数据";
    }
}
3 AMD处理器类
public class IntelCpu implements Cpu {

    public void run() {
        System.out.println("使用AMD处理器");
    }
}
4 金士顿内存条
public class KingstonMemory implements Memory {

    public void save() {
        System.out.println("使用金士顿作为内存条");
    }
}
5 测试类
public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.setHardDisk(new XiJieHardDisk());
        // computer.setCpu(new IntelCpu());
        computer.setCpu(new AMDCpu());
        computer.setMemory(new KingstonMemory());

        computer.run();
    }
}
6 结果
计算机工作
使用AMD处理器
使用金士顿作为内存条
使用希捷希捷硬盘取数据
从硬盘中获取的数据为:数据

根据依赖倒转原则 , 我们只需要修改Computer类,让Computer类依赖抽象(各个配件的接口),而不是依赖于各个组件具体的实现类即可.

4 接口隔离原则

客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上.

1 案例

以安全门为例,安全门有防水防盗的功能, 小牛牌安全门具备上述所有功能

1 安全门接口
public interface SafeDoor {
	void antiTheft();
    void fireproof();
    void waterproof();
}
2 小牛牌
public class XiaoNiuDoor implements SafeDoor {
      @Override
    public void antiTheft() {
       
    }
        @Override
    public void fireproof() {
       
    }
        @Override
    public void fireproof() {
       
    }
}

此时,出现了一个小狗牌,他只能防水防盗,没有防火功能,就不好处理

2 案例改造 1 防盗接口
public interface AntiTheft {
    void antiTheft();
}
2 防火接口
public interface Fireproof {
    void fireproof();
}
3 防水接口
public interface Waterproof {
    void waterproof();
}
4 小狗牌
public class XiaoGouDoor implements AntiTheft, Waterproof{
      @Override
    public void antiTheft() {
       
    }
        @Override
    public void fireproof() {
       
    }
}

将所有功能分开到不同的接口中,类需要那种功能就实现那种接口.

5 迪米特法则

迪米特法则又叫最少知识原则. 如果两个实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用.

1 案例

以 明星,经纪人,粉丝,广告公司之间为例, 明星和粉丝见面由经纪人安排,明星和广告公司合作由经纪人安排,所以通过经纪人将三者关联.

1 明星类
public class Star {
    private String name;

    public Star(String name) {
        this.name=name;
    }

    public String getName() {
        return name;
    }
}
2 粉丝类
public class Fans {
    private String name;

    public Fans(String name) {
        this.name=name;
    }

    public String getName() {
        return name;
    }
}
3 广告公司类
public class Company {
    private String name;

    public Company(String name) {
        this.name=name;
    }

    public String getName() {
        return name;
    }
}
4 经纪人类
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() + "商谈业务。");
    }
}

通过经纪人, 将明星和粉丝, 公告公司关联起来,实现最少关联.

6 合成复用原则

合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现.

1 案例

以汽车分类划分, 车按照动力分,汽油车,电动车; 按照颜色分,红车,白车.

1 按照继承关系来划分 1 汽车类
public class Car {
    public void move(){
    }
}
2 油车
public class PetroCar extends  Car{
    @Override
    public void move() {
        super.move();
    }
}
3 红色油车
public class RedPetroCar extends  PetroCar{
    @Override
    public void move() {
        super.move();
    }
}
4 白色油车
public class WhitePetroCar extends  PetroCar{
    @Override
    public void move() {
        super.move();
    }
}
5 电车
public class EleCar extends Car {
    @Override
    public void move() {
        super.move();
    }
}
6 红色电车
public class RedEleCar extends Car {
    @Override
    public void move() {
        super.move();
    }
}
7 白色电车
public class WhiteEleCar extends EleCar  {
    @Override
    public void move() {
        super.move();
    }
}

如果出现新的氢能源车 ,又得新增三个类.

2 按照聚合复用关系来划分

把颜色抽象成接口,聚合复用到汽车类中.

1 颜色接口
public interface Color {
}
2 汽车类
public class Car {
    private Color color;
    public void move(){

    }

}

然后油车, 电车可以传入不同的颜色,构造出不同颜色的车型. 如果新增氢能源车,也只需要新增一个类即可.

所以, 在类机构设计时尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/733799.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存