JAVA中的六大设计原则

1.单一职责原则(LSP)

单一职责原则的含义是:只能让一个类有且只有一个职责,因为如果有两个职责,当职责1发生改变,需要修改这个类的代码时,这个修改有可能会导致职责2的运行发生问题。

单一职责的优点是分类清晰,适用于接口、类、方法,一个类一个方法只完成一件事情,避免了代码耦合出现的问题。但是分得太细又会人为地增加系统的复杂性,为开发制造了麻烦。

/**
 * 不使用单一职责设计原则的接口,所有的方法都汇聚在一个类中
 * */
interface IUserInfo {
    String getUserID();
    void setUserID(String userID);
    String getUserName();
    void setUserName(String userName);
    String getPassword();
    void setPassword(String password);
    boolean deleteUser();
    boolean changePassword(String oldlPassword);
}
/**
 *使用单一职责设计原则,根据用户行为和用户属性为职责,将接口一分为二,
 * 分为用户属性接口IUserBO和用户行为接口IUserBiz
 * */
interface IUserBO {
    String getUserID();
    void setUserID(String userID);
    String getUserName();
    void setUserName(String userName);
    String getPassword();
    void setPassword(String password);
}
interface IUserBiz {
    boolean deleteUser();
    boolean changePassword(String oldlPassword);
}

2.里氏替换原则(LSP)

里氏替换原则针对的是有继承关系的子类和父类,为了减少继承的弊端而生,含义是只要有父亲出现的地方子类就可以出现,并且替换为子类也不会有任何错误(相反父亲未必就能完美替换子类)。

为了达成这个目的,子类就必须要实现父类的所有方法,即父类的方法必须是子类全部需要的、在调用时,必须使用父亲/接口、子类可以有自己的个性、实现父类的方法时输入参数可以被放大、实现父类的输出结果时结果可以缩小。
里氏替换的优点是让继承得到最大作用发挥,并减少继承的弊端,缺点是不太灵活。

/**
 * 邮件发送接口
 * */
class EmailSend {
    void send(CommonUser user){
        System.out.println(user.getUserName() + "发送邮件");
    }
}
/**
 * 普通用户发送邮件实现类
 * */
class CommonUserEmailSend extends EmailSend {

    public void send(User user) {
        System.out.println(user.getUserName() + "发送邮件。");
    }
    public void common(){
        System.out.println("我是普通用户。");
    }
}

3.依赖倒置原则(DIP)

依赖倒置原则的定义是,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的,也就是面向接口编程。

依赖倒置原则的优点是,通过接口使各个类或模块彼此间独立,不相互影响,实现模块之间的松耦合。缺点是增加了额外维护接口和类的工作量。

/**
 *司机接口
 * */
interface IDriver {
    public void drive(ICar car);
}
/**
 *汽车接口
 * */
interface ICar {
    public void run();
}
/**
 *司机实现类
 * */
class Driver implements IDriver {

    @Override
    public void drive(ICar car) {
        car.run();
    }
}
/**
 * 宝马车
 * */
class Benz implements ICar {

    @Override
    public void run() {
        System.out.println("开奔驰车");
    }
}
/**
 * 奔驰车
 * */
class BMW implements ICar {

    @Override
    public void run() {
        System.out.println("开宝马车");
    }
}

4.接口隔离原则(ISP)

接口隔离的原则是,建立单一的接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。

每个模块都应该是单一的接口,提供给几个模块就应该有几个接口,也就是接口模块化、独立化。
与单一职责原则不一样,单一职责原则中,一个接口可以有多个方法,这多个方法提供给多个模块访问,而接口隔离原则则是倡导一个模块使用一个一个接口,而不是所有的方法都放在同一个接口中。

这样的设计原则虽然可以让系统内聚提高,但是也增加了结构的复杂化,导致开发难度增加。

/**
 * 老师接口
 * */
interface DoWorkT {
    //改作业
    void correctingHomework(int studentID);
}
/**
 * 学生接口
 * */
interface DoWorkS {
    // 做作业
    public void doHomeWork();
}
/**
 * 老师、学生公共接口
 * */
interface DoWorkC {
    //上课
    void attendClass();
}
/**
 * 老师实现工作接口、上课接口
 * */
class Teacher implements DoWorkT ,DoWorkC{
    private int teacherID;
    @Override
    public void correctingHomework(int StudentID) {
        System.out.println("老师改作业");
    }
    @Override
    public void attendClass() {
        System.out.println("老师上课.");
    }
}
/**
 * 学生实现写作业接口、上课接口
 * */
class Student implements DoWorkS, DoWorkC {
    private int studentID;

    @Override
    public void doHomeWork() {
        System.out.println("学生写作业");
    }
    @Override
    public void attendClass() {
        System.out.println("学生上课");
    }
}

5.迪米特法则(LOD)

迪米特法则又称最少知道法则,也就是一个对象应该对其他对象有最少的理解,即一个类应该对自己需要耦合或需要调用的类知道的最少。可以降低系统之间的耦合,提高系统的健壮性。

在下面这个例子中,明星类和粉丝类要发生通信,就需要一个经纪人的中间类,从而达到了最少知道法则。这样虽然能降低耦合度,但是也大大提高了系统复杂性。

public class Test {
    public static void main(String[] args) {
        Agent agent = new Agent();
        agent.setMyStar(new Star("周杰伦"));
        agent.setMyFans(new Fans("粉丝"));
        agent.meeting();
    }
}
/**经纪人*/
class Agent {
    private Star myStar;
    private Fans myFans;
    public void setMyStar(Star myStar) {
        this.myStar = myStar;
    }
    public void setMyFans(Fans myFans) {
        this.myFans = myFans;
    }
    public void meeting(){
        System.out.println(myFans.getName() + ",与明星" + myStar.getName() + "见面了");
    }
}
/**明星*/
class Star {
    private String name;
    Star(String name) {
        this.name = name;
    }
    public String getName(){
        return name;
    }
}
/**粉丝*/
class Fans {
    private String name;
    Fans(String name) {
        this.name = name;
    }
    String getName(){
        return name;
    }
}

6.开闭原则(OCP)

开闭原则也就是,软件实体(类、模块、方法)应该对扩展开发,对修改关闭,也就是软件需要变化时,尽量通过拓展软件实体的行为来实现,而不是修改已有的代码。

开闭原则是面向对象设计的终极目标,其他原则可以看做是开闭原则的实现方法。

/**书籍接口*/
interface IBook {
    public String getName();
    public int getPrice();
    public String getAuthor();
}
/**小说类,实现了书籍接口*/
class NovelBook implements IBook {
    private String name;
    private int price;
    private String author;
    public NovelBook(String name, int price, String author) {
        this.name = name;
        this.price = price;
        this.author = author;
    }
    @Override
    public String getName() {
        return this.name;
    }
    @Override
    public int getPrice() {
        return this.price;
    }
    @Override
    public String getAuthor() {
        return this.author;
    }
}
/**测试类*/
public class BookStore {
    private static List<IBook> books = new ArrayList<IBook>();
    //使用构造函数初始化books
    public BookStore(){
        books.add(new NovelBook("小说A", 3200, "作者A"));
        books.add(new NovelBook("小说B", 5600, "作者B"));
        books.add(new NovelBook("小说C", 3500, "作者C"));
        books.add(new NovelBook("小说D", 4300, "作者D"));
    }  
    // 模拟书店卖书
    public static void main(String[] args) {
        for (IBook book : books) {
            System.out.println("书籍名称:" + book.getName() + "\t书籍作者"
                    + book.getAuthor() + "\t书籍价格"
                    + book.getPrice() + "元");
        }
    }
}

在上面的例子中,如果要对小说类数据打折处理,一般是通过修改接口达到目的,这里按照OCP原则,新增一个子类,重写getPrice方法实现打折需求。

/**为实现小说打折处理增加的子类,打折小说类*/
class OffNovelBook extends NovelBook {
    public OffNovelBook(String name, int price, String author) {
        super(name, price, author);
    }
    // 重写getPrice
    @Override
    public int getPrice() {
        // 获取原价
        int price = super.getPrice();
        // 跳楼价,统统五折
        int offPrice = price / 2;
        return offPrice;
    }
}
public class BookStore {
    private static List<IBook> books = new ArrayList<IBook>();
    //使用构造函数初始化books
    public BookStore(){
        books.add(new OffNovelBook("小说A", 3200, "作者A"));
        books.add(new OffNovelBook("小说B", 5600, "作者B"));
        books.add(new OffNovelBook("小说C", 3500, "作者C"));
        books.add(new OffNovelBook("小说D", 4300, "作者D"));
    }
    ...
}

总结

合适的使用恰当的设计原则可以达到更好的代码重用性、可读性、可靠性、可维护性,但是不恰当的使用也有可能导致系统太过复杂,反而降低开发效率。有一些设计原则可以一起使用,而有一些又相互排斥。比如接口隔离原则和单一职责原则。而其他五个原则都可以看做是为了实现开闭原则的途径。

达到低耦合、高内聚、可开闭是设计模式的终极目标。

表格总结
设计原则名称定 义使用频率
单一职责原则(LSP)一个类只负责一个职责职责★★★★☆
里氏替换原则(LSP)所有引用基类对象的地方能够透明地使用其子类的对象★★★★★
依赖倒置原则(DIP)把依赖放到接口上,面向接口编程★★★★★
接口隔离原则(ISP)使用多个专门的接口,而不使用单一的总接口★★★★★
迪米特法则(LOD)一个软件实体应当尽可能少地与其他实体发生相互作用★★★☆☆
开闭原则(OCP)软件实体应对扩展开放,而对修改关闭★★★★★
参考

六大设计原则详解

设计原则总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>