设计模式六大原则

news2024/9/25 17:17:07

设计模式六大原则

1.单⼀职责( ⼀个类和⽅法只做⼀件事 )

不遵守单一职责原则

模拟不同用户观看视频,先一把梭哈,所有用户观看视频的服务全部都写道一块

public class ApiTest {

    public static void main(String[] args) {
        VideoUserService service = new VideoUserService();
        service.serveGrade("VIP用户");
        service.serveGrade("普通用户");
        service.serveGrade("访客用户");
    }

}
public class VideoUserService {

    public void serveGrade(String userType){
        if ("VIP用户".equals(userType)){
            System.out.println("VIP用户,视频1080P蓝光");
        } else if ("普通用户".equals(userType)){
            System.out.println("普通用户,视频720P超清");
        } else if ("访客用户".equals(userType)){
            System.out.println("访客用户,视频480P高清");
        }
    }

}

遵守单一职责原则

根据用户角色进行分类实现

public class ApiTest {

    public static void main(String[] args) {
        IVideoUserService guest = new GuestVideoUserService();
        guest.advertisement();
        guest.definition();
        IVideoUserService ordinary = new OrdinaryVideoUserService();
        ordinary.advertisement();
        ordinary.definition();

        IVideoUserService vip = new VipVideoUserService();
        vip.advertisement();
        vip.definition();
    }

}
//视频服务接口
public interface IVideoUserService {

    void definition();

    void advertisement();

}
//访客用户
public class GuestVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("访客用户,视频480P高清");
    }

    public void advertisement() {
        System.out.println("访客用户,视频有广告");
    }

}
//普通用户
public class OrdinaryVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("普通用户,视频720P超清");
    }

    public void advertisement() {
        System.out.println("普通用户,视频有广告");
    }
}
//VIP用户
public class VipVideoUserService implements IVideoUserService {

    public void definition() {
        System.out.println("VIP用户,视频1080P蓝光");
    }

    public void advertisement() {
        System.out.println("VIP会员,视频无广告");
    }
}

2.⾥⽒替换( 多态,⼦类可扩展⽗类 )

⾥⽒替换原则,继承必须确保超类锁拥有的性质在子类中依然成立。

没有遵守⾥⽒替换原则的情况

下面的例子中CashCard储蓄卡具备:提现、存储的功能,而它的子类CreditCard信用卡继承了储蓄卡,但在功能上存在差异对父类的方法进行了重写,因此子类CreditCard中

父类CashCard的拥有的性质已经被破坏了。

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    //模拟储蓄卡
    @Test
    public void test_CashCard() {
        CashCard cashCard = new CashCard();
        // 提现
        cashCard.withdrawal("100001", new BigDecimal(100));
        // 储蓄
        cashCard.recharge("100001", new BigDecimal(100));
        // 交易流水
        List<String> tradeFlow = cashCard.tradeFlow();
        logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
    }


    //模拟信用卡
    @Test
    public void test_CreditCard() {
        CreditCard creditCard = new CreditCard();
        // 支付
        creditCard.withdrawal("100001", new BigDecimal(100));
        // 还款
        creditCard.recharge("100001", new BigDecimal(100));
        // 交易流水
        List<String> tradeFlow = creditCard.tradeFlow();
        logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
    }

}
//储蓄卡
public class CashCard {

    private Logger logger = LoggerFactory.getLogger(CashCard.class);

    /**
     * 提现
     *
     * @param orderId 单号
     * @param amount  金额
     * @return 状态码 0000成功、0001失败、0002重复
     */
    public String withdrawal(String orderId, BigDecimal amount) {
        // 模拟支付成功
        logger.info("提现成功,单号:{} 金额:{}", orderId, amount);
        return "0000";
    }

    /**
     * 储蓄
     *
     * @param orderId 单号
     * @param amount  金额
     */
    public String recharge(String orderId, BigDecimal amount) {
        // 模拟充值成功
        logger.info("储蓄成功,单号:{} 金额:{}", orderId, amount);
        return "0000";
    }

    /**
     * 交易流水查询
     * @return 交易流水
     */
    public List<String> tradeFlow() {
        logger.info("交易流水查询成功");
        List<String> tradeList = new ArrayList<String>();
        tradeList.add("100001,100.00");
        tradeList.add("100001,80.00");
        tradeList.add("100001,76.50");
        tradeList.add("100001,126.00");
        return tradeList;
    }

}
//信用卡
public class CreditCard extends CashCard {

    private Logger logger = LoggerFactory.getLogger(CashCard.class);

    @Override
    public String withdrawal(String orderId, BigDecimal amount) {
        // 校验
        if (amount.compareTo(new BigDecimal(1000)) >= 0){
            logger.info("贷款金额校验(限额1000元),单号:{} 金额:{}", orderId, amount);
            return "0001";
        }
        // 模拟生成贷款单
        logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);
        // 模拟支付成功
        logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);
        return "0000";
    }

    @Override
    public String recharge(String orderId, BigDecimal amount) {
        // 模拟生成还款单
        logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);
        // 模拟还款成功
        logger.info("还款成功,单号:{} 金额:{}", orderId, amount);
        return "0000";
    }

    @Override
    public List<String> tradeFlow() {
        return super.tradeFlow();
    }

}

遵守⾥⽒替换原则

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_bankCard() {
        logger.info("里氏替换前,CashCard类:");
        CashCard bankCard = new CashCard("6214567800989876", "2022-03-05");
        // 提现
        bankCard.withdrawal("100001", new BigDecimal(100));
        // 储蓄
        bankCard.recharge("100001", new BigDecimal(100));

        logger.info("里氏替换后,CreditCard类:");
        CashCard creditCard = new CreditCard("6214567800989876", "2022-03-05");
        // 提现
        creditCard.withdrawal("100001", new BigDecimal(1000000));
        // 储蓄
        creditCard.recharge("100001", new BigDecimal(100));
    }

    @Test
    public void test_CreditCard(){
        CreditCard creditCard = new CreditCard("6214567800989876", "2022-03-05");
        // 支付,贷款
        creditCard.loan("100001", new BigDecimal(100));
        // 还款
        creditCard.repayment("100001", new BigDecimal(100));
    }

}
//模拟银行卡
public abstract class BankCard {

    private Logger logger = LoggerFactory.getLogger(BankCard.class);

    private String cardNo;   // 卡号
    private String cardDate; // 开卡时间

    public BankCard(String cardNo, String cardDate) {
        this.cardNo = cardNo;
        this.cardDate = cardDate;
    }

    abstract boolean rule(BigDecimal amount);

    // 正向入账,+ 钱
    public String positive(String orderId, BigDecimal amount) {
        // 入款成功,存款、还款
        logger.info("卡号{} 入款成功,单号:{} 金额:{}", cardNo, orderId, amount);
        return "0000";
    }

    // 逆向入账,- 钱
    public String negative(String orderId, BigDecimal amount) {
        // 入款成功,存款、还款
        logger.info("卡号{} 出款成功,单号:{} 金额:{}", cardNo, orderId, amount);
        return "0000";
    }

    /**
     * 交易流水查询
     *
     * @return 交易流水
     */
    public List<String> tradeFlow() {
        logger.info("交易流水查询成功");
        List<String> tradeList = new ArrayList<String>();
        tradeList.add("100001,100.00");
        tradeList.add("100001,80.00");
        tradeList.add("100001,76.50");
        tradeList.add("100001,126.00");
        return tradeList;
    }

    public String getCardNo() {
        return cardNo;
    }

    public String getCardDate() {
        return cardDate;
    }
}
//存储卡
public class CashCard extends BankCard {

    private Logger logger = LoggerFactory.getLogger(CashCard.class);

    public CashCard(String cardNo, String cardDate) {
        super(cardNo, cardDate);
    }

    boolean rule(BigDecimal amount) {
        return true;
    }

    /**
     * 提现
     *
     * @param orderId 单号
     * @param amount  金额
     * @return 状态码 0000成功、0001失败、0002重复
     */
    public String withdrawal(String orderId, BigDecimal amount) {
        // 模拟支付成功
        logger.info("提现成功,单号:{} 金额:{}", orderId, amount);
        return super.negative(orderId, amount);
    }

    /**
     * 储蓄
     *
     * @param orderId 单号
     * @param amount  金额
     */
    public String recharge(String orderId, BigDecimal amount) {
        // 模拟充值成功
        logger.info("储蓄成功,单号:{} 金额:{}", orderId, amount);
        return super.positive(orderId, amount);
    }

    /**
     * 风险校验
     *
     * @param cardNo  卡号
     * @param orderId 单号
     * @param amount  金额
     * @return 状态
     */
    public boolean checkRisk(String cardNo, String orderId, BigDecimal amount) {
        // 模拟风控校验
        logger.info("风控校验,卡号:{} 单号:{} 金额:{}", cardNo, orderId, amount);
        return true;
    }

}
//信用卡
public class CreditCard extends CashCard {

    private Logger logger = LoggerFactory.getLogger(CreditCard.class);

    public CreditCard(String cardNo, String cardDate) {
        super(cardNo, cardDate);
    }

    boolean rule2(BigDecimal amount) {
        return amount.compareTo(new BigDecimal(1000)) <= 0;
    }

    /**
     * 提现,信用卡贷款
     *
     * @param orderId 单号
     * @param amount  金额
     * @return 状态码
     */
    public String loan(String orderId, BigDecimal amount) {
        boolean rule = rule2(amount);
        if (!rule) {
            logger.info("生成贷款单失败,金额超限。单号:{} 金额:{}", orderId, amount);
            return "0001";
        }
        // 模拟生成贷款单
        logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);
        // 模拟支付成功
        logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);
        return super.negative(orderId, amount);

    }

    /**
     * 还款,信用卡还款
     *
     * @param orderId 单号
     * @param amount  金额
     * @return 状态码
     */
    public String repayment(String orderId, BigDecimal amount) {
        // 模拟生成还款单
        logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);
        // 模拟还款成功
        logger.info("还款成功,单号:{} 金额:{}", orderId, amount);
        return super.positive(orderId, amount);
    }

}

3.依赖倒置( 细节依赖抽象,下层依赖上层 )

程序要依赖于抽象接口,不要依赖于具体的实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样降低了客户与实现模块间的耦合。

image-20221229210525321

不遵守依赖倒置原则

模拟抽奖,在drawControl类中既要去实现随机抽奖又要去实现权重抽奖,如果后续扩展还需要去实现其他的抽奖方式。

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_DrawControl(){
        List<BetUser> betUserList = new ArrayList<>();
        betUserList.add(new BetUser("花花", 65));
        betUserList.add(new BetUser("豆豆", 43));
        betUserList.add(new BetUser("小白", 72));
        betUserList.add(new BetUser("笨笨", 89));
        betUserList.add(new BetUser("丑蛋", 10));

        DrawControl drawControl = new DrawControl();
        List<BetUser> prizeRandomUserList = drawControl.doDrawRandom(betUserList, 3);
        logger.info("随机抽奖,中奖用户名单:{}", JSON.toJSON(prizeRandomUserList));

        List<BetUser> prizeWeightUserList = drawControl.doDrawWeight(betUserList, 3);
        logger.info("权重抽奖,中奖用户名单:{}", JSON.toJSON(prizeWeightUserList));
    }

}
public class BetUser {

    private String userName;  // 用户姓名
    private int userWeight;   // 用户权重

    public BetUser() {
    }

    public BetUser(String userName, int userWeight) {
        this.userName = userName;
        this.userWeight = userWeight;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserWeight() {
        return userWeight;
    }

    public void setUserWeight(int userWeight) {
        this.userWeight = userWeight;
    }
}
public class DrawControl {

    // 随机抽取指定数量的用户,作为中奖用户
    public List<BetUser> doDrawRandom(List<BetUser> list, int count) {
        // 集合数量很小直接返回
        if (list.size() <= count) return list;
        // 乱序集合
        Collections.shuffle(list);
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }

    // 权重排名获取指定数量的用户,作为中奖用户
    public List<BetUser> doDrawWeight(List<BetUser> list, int count) {
        // 按照权重排序
        list.sort((o1, o2) -> {
            int e = o2.getUserWeight() - o1.getUserWeight();
            if (0 == e) return 0;
            return e > 0 ? 1 : -1;
        });
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }

}

遵守依赖倒置原则

定义一个抽奖接口,不同的抽奖方式各自去实现抽奖接口,DrawControl则只是提供一个抽奖操作去获取抽奖的结果,不在关心抽奖的实现。

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_DrawControl() {
        List<BetUser> betUserList = new ArrayList<>();
        betUserList.add(new BetUser("花花", 65));
        betUserList.add(new BetUser("豆豆", 43));
        betUserList.add(new BetUser("小白", 72));
        betUserList.add(new BetUser("笨笨", 89));
        betUserList.add(new BetUser("丑蛋", 10));

        DrawControl drawControl = new DrawControl();
        List<BetUser> prizeRandomUserList = drawControl.doDraw(new DrawRandom(), betUserList, 3);
        logger.info("随机抽奖,中奖用户名单:{}", JSON.toJSON(prizeRandomUserList));

        List<BetUser> prizeWeightUserList = drawControl.doDraw(new DrawWeightRank(), betUserList, 3);
        logger.info("权重抽奖,中奖用户名单:{}", JSON.toJSON(prizeWeightUserList));
    }

}
public class BetUser {

    private String userName;  // 用户姓名
    private int userWeight;   // 用户权重

    public BetUser() {
    }

    public BetUser(String userName, int userWeight) {
        this.userName = userName;
        this.userWeight = userWeight;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserWeight() {
        return userWeight;
    }

    public void setUserWeight(int userWeight) {
        this.userWeight = userWeight;
    }
}
public class DrawControl {

    private IDraw draw;

    public List<BetUser> doDraw(IDraw draw, List<BetUser> betUserList, int count) {
        return draw.prize(betUserList, count);
    }

}
public class DrawRandom implements IDraw {

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {
        // 集合数量很小直接返回
        if (list.size() <= count) return list;
        // 乱序集合
        Collections.shuffle(list);
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }

}
public class DrawWeightRank implements IDraw {

    @Override
    public List<BetUser> prize(List<BetUser> list, int count) {
        // 按照权重排序
        list.sort((o1, o2) -> {
            int e = o2.getUserWeight() - o1.getUserWeight();
            if (0 == e) return 0;
            return e > 0 ? 1 : -1;
        });
        // 取出指定数量的中奖用户
        List<BetUser> prizeList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            prizeList.add(list.get(i));
        }
        return prizeList;
    }

}
public interface IDraw {

    List<BetUser> prize(List<BetUser> list, int count);

}

4.接⼝隔离( 建⽴单⼀接⼝ )

要求程序员尽量将臃肿庞大的接口拆分为更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

不遵守接口隔离原则

模拟游戏中的两个英雄,后裔和廉颇他们各自由各自的技能;比如,

后裔具备:射箭、隐身、沉默技能

廉颇具备:隐身、沉默、眩晕技能

而ISkill接口定义了四个技能,射箭、隐身、沉默、眩晕

HeroHouYi和HeroLianPo去实现接口时必须强制的去实现这个四个方法,而其中某一个方法又不是必须的

public class ApiTest {

    @Test
    public void test_ISkill(){
        // 后裔
        HeroHouYi heroHouYi = new HeroHouYi();
        heroHouYi.doArchery();

        // 廉颇
        HeroLianPo heroLianPo = new HeroLianPo();
        heroLianPo.doInvisible();
    }

}
public class HeroHouYi implements ISkill{
	
    //射箭
    @Override
    public void doArchery() {
        System.out.println("后裔的灼日之矢");
    }
	
    //隐身
    @Override
    public void doInvisible() {
        System.out.println("后裔的隐身技能");
    }
	
    //沉默
    @Override
    public void doSilent() {
        System.out.println("后裔的沉默技能");
    }
	
    //眩晕
    @Override
    public void doVertigo() {
        // 无此技能的实现
    }

}
public class HeroLianPo implements ISkill{

    @Override
    public void doArchery() {
        // 无此技能的实现
    }

    @Override
    public void doInvisible() {
        System.out.println("廉颇的隐身技能");
    }

    @Override
    public void doSilent() {
        System.out.println("廉颇的沉默技能");
    }

    @Override
    public void doVertigo() {
        System.out.println("廉颇的眩晕技能");
    }

}
public interface ISkill {

    // 射箭
    void doArchery();

    // 隐袭
    void doInvisible();

    // 沉默
    void doSilent();

    // 眩晕
    void doVertigo();

}

遵守接口隔离原则

我们将每个技能都抽象成一个接口,HeroHouYi和HeroLianPo各自实现自己具备技能的接口去做实现

public class ApiTest {

    @Test
    public void test_ISkill(){
        // 后裔
        HeroHouYi heroHouYi = new HeroHouYi();
        heroHouYi.doArchery();

        // 廉颇
        HeroLianPo heroLianPo = new HeroLianPo();
        heroLianPo.doInvisible();
    }

}
public class HeroHouYi implements ISkillArchery, ISkillInvisible, ISkillSilent {

    @Override
    public void doArchery() {
        System.out.println("后裔的灼日之矢");
    }

    @Override
    public void doInvisible() {
        System.out.println("后裔的隐身技能");
    }

    @Override
    public void doSilent() {
        System.out.println("后裔的沉默技能");
    }

}
public class HeroLianPo implements ISkillInvisible, ISkillSilent, ISkillVertigo {

    @Override
    public void doInvisible() {
        System.out.println("廉颇的隐身技能");
    }

    @Override
    public void doSilent() {
        System.out.println("廉颇的沉默技能");
    }

    @Override
    public void doVertigo() {
        System.out.println("廉颇的眩晕技能");
    }

}
public interface ISkillArchery {

    // 射箭
    void doArchery();

}
public interface ISkillInvisible {

    // 隐袭
    void doInvisible();

}
public interface ISkillSilent {

    // 沉默
    void doSilent();

}
public interface ISkillVertigo {

    // 眩晕
    void doVertigo();

}

5.迪⽶特原则( 最少知道,降低耦合 )

意义在于降低类之间的耦合。由于每个对象尽量减少对其他对象的了解,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或者很少有)依赖关系。

不遵守迪米特原则

模拟校长要查看3年1班级分数,统计班级信息、学生分数的工作本应该老师来做,而校长只需要通过老师取获取这些信息,这里校长又要去查询老师的信息又要去统计班级的信息以及学生的分数。

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_Principal() {
        Principal principal = new Principal();
        Map<String, Object> map = principal.queryClazzInfo("3年1班");
        logger.info("查询结果:{}", JSON.toJSONString(map));
    }

}
//校长
public class Principal {

    private Teacher teacher = new Teacher("丽华", "3年1班");

    // 查询班级信息,总分数、学生人数、平均值
    public Map<String, Object> queryClazzInfo(String clazzId) {
        // 获取班级信息;学生总人数、总分、平均分
        int stuCount = clazzStudentCount();
        double totalScore = clazzTotalScore();
        double averageScore = clazzAverageScore();

        // 组装对象,实际业务开发会有对应的类
        Map<String, Object> mapObj = new HashMap<>();
        mapObj.put("班级", teacher.getClazz());
        mapObj.put("老师", teacher.getName());
        mapObj.put("学生人数", stuCount);
        mapObj.put("班级总分数", totalScore);
        mapObj.put("班级平均分", averageScore);
        return mapObj;
    }

    // 总分
    public double clazzTotalScore() {
        double totalScore = 0;
        for (Student stu : Teacher.getStudentList()) {
            totalScore += stu.getGrade();
        }
        return totalScore;
    }

    // 平均分
    public double clazzAverageScore(){
        double totalScore = 0;
        for (Student stu : Teacher.getStudentList()) {
            totalScore += stu.getGrade();
        }
        return totalScore / Teacher.getStudentList().size();
    }

    // 班级人数
    public int clazzStudentCount(){
        return Teacher.getStudentList().size();
    }

}
//老师
public class Teacher {

    private String name;                // 老师名称
    private String clazz;               // 班级
    private static List<Student> studentList;  // 学生

    public Teacher() {
    }

    public Teacher(String name, String clazz) {
        this.name = name;
        this.clazz = clazz;
    }

    static {
        studentList = new ArrayList<>();
        studentList.add(new Student("花花", 10, 589));
        studentList.add(new Student("豆豆", 54, 356));
        studentList.add(new Student("秋雅", 23, 439));
        studentList.add(new Student("皮皮", 2, 665));
        studentList.add(new Student("蛋蛋", 19, 502));
    }

    public static List<Student> getStudentList() {
        return studentList;
    }

    public String getName() {
        return name;
    }

    public String getClazz() {
        return clazz;
    }
}
//学生
public class Student {

    private String name;    // 学生姓名
    private int rank;       // 考试排名(总排名)
    private double grade;   // 考试分数(总分)

    public Student() {
    }

    public Student(String name, int rank, double grade) {
        this.name = name;
        this.rank = rank;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    public double getGrade() {
        return grade;
    }

    public void setGrade(double grade) {
        this.grade = grade;
    }
}

遵守迪米特原则

校长查看3年1班的信息,只需要通过老师,统计的数据由老师去做;校长并不需要过多的去了解学生类的信息

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_Principal() {
        Principal principal = new Principal();
        Map<String, Object> map = principal.queryClazzInfo("3年1班");
        logger.info("查询结果:{}", JSON.toJSONString(map));
    }

}
//校长
public class Principal {

    private Teacher teacher = new Teacher("丽华", "3年1班");

    // 查询班级信息,总分数、学生人数、平均值
    public Map<String, Object> queryClazzInfo(String clazzId) {
        // 获取班级信息;学生总人数、总分、平均分
        int stuCount = teacher.clazzStudentCount();
        double totalScore = teacher.clazzTotalScore();
        double averageScore = teacher.clazzAverageScore();

        // 组装对象,实际业务开发会有对应的类
        Map<String, Object> mapObj = new HashMap<>();
        mapObj.put("班级", teacher.getClazz());
        mapObj.put("老师", teacher.getName());
        mapObj.put("学生人数", stuCount);
        mapObj.put("班级总分数", totalScore);
        mapObj.put("班级平均分", averageScore);
        return mapObj;
    }
}
//老师
public class Teacher {

    private String name;                // 老师名称
    private String clazz;               // 班级
    private static List<Student> studentList;  // 学生

    public Teacher() {
    }

    public Teacher(String name, String clazz) {
        this.name = name;
        this.clazz = clazz;
    }

    static {
        studentList = new ArrayList<>();
        studentList.add(new Student("花花", 10, 589));
        studentList.add(new Student("豆豆", 54, 356));
        studentList.add(new Student("秋雅", 23, 439));
        studentList.add(new Student("皮皮", 2, 665));
        studentList.add(new Student("蛋蛋", 19, 502));
    }

    // 总分
    public double clazzTotalScore() {
        double totalScore = 0;
        for (Student stu : studentList) {
            totalScore += stu.getGrade();
        }
        return totalScore;
    }

    // 平均分
    public double clazzAverageScore(){
        double totalScore = 0;
        for (Student stu : studentList) {
            totalScore += stu.getGrade();
        }
        return totalScore / studentList.size();
    }

    // 班级人数
    public int clazzStudentCount(){
        return studentList.size();
    }

    public static List<Student> getStudentList() {
        return studentList;
    }

    public String getName() {
        return name;
    }

    public String getClazz() {
        return clazz;
    }
}
//学生
public class Student {

    private String name;    // 学生姓名
    private int rank;       // 考试排名(总排名)
    private double grade;   // 考试分数(总分)

    public Student() {
    }

    public Student(String name, int rank, double grade) {
        this.name = name;
        this.rank = rank;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    public double getGrade() {
        return grade;
    }

    public void setGrade(double grade) {
        this.grade = grade;
    }
}

6.开闭原则( 抽象架构,扩展实现 )

开闭原则规定“软件中的对象(类,模块,函数等等)”应该对于扩展开放,对于修改关闭

比如:下面计算圆的面积,CalculationArea类的π是3.14D,而我希望用π是3.141592653D来计算圆的面积,

如果直接修改CalculationArea类的π的值就会对其他要求π以3.14D计算圆的面积的地方造成影响;

因此,我们添加CalculationAreaExt这个扩展类去继承CalculationArea重写计算圆的方法用子类的π值取计算圆的面积

public class ApiTest {

    @Test
    public void test_CalculationAreaExt(){
        ICalculationArea area = new CalculationAreaExt();
        double circular = area.circular(10);
        System.out.println(circular);
    }

}
public interface ICalculationArea {

    /**
     * 计算面积,长方形
     *
     * @param x 长
     * @param y 宽
     * @return 面积
     */
    double rectangle(double x, double y);

    /**
     * 计算面积,三角形
     * @param x 边长x
     * @param y 边长y
     * @param z 边长z
     * @return  面积
     *
     * 海伦公式:S=√[p(p-a)(p-b)(p-c)] 其中:p=(a+b+c)/2
     */
    double triangle(double x, double y, double z);

    /**
     * 计算面积,圆形
     * @param r 半径
     * @return 面积
     *
     * 圆面积公式:S=πr²
     */
    double circular(double r);

}
public class CalculationArea implements ICalculationArea {

    private final static double π = 3.14D;

    public double rectangle(double x, double y) {
        return x * y;
    }

    public double triangle(double x, double y, double z) {
        double p = (x + y + z) / 2;
        return Math.sqrt(p * (p - x) * (p - y) * (p - z));
    }

    public double circular(double r) {
        return π * r * r;
    }

}
public class CalculationAreaExt extends CalculationArea {

    private final static double π = 3.141592653D;

    @Override
    public double circular(double r) {
        return π * r * r;
    }

}

设计模式分类

1. 创建型模式

这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性。

image-20221228220333191

2. 结构型模式

这类模式介绍如何将对象和类组装成较⼤的结构, 并同时保持结构的灵活和⾼效。

image-20221228220218383

3. ⾏为模式

这类模式负责对象间的⾼效沟通和职责委派。

image-20221228220522415

image-20221228220445136

image-20221228220457538

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/127437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

干货丨FPGA零基础学习,入门必看!

看到不少同学后台进行提问&#xff1a;FPGA如何入门&#xff1f;怎么学习&#xff1f;其实对于新人来说&#xff0c;FPGA的学习需要了解的东西还是非常多&#xff0c;下面IC修真院就带大家一起来了解一下吧。 FPGA简介 FPGA普遍用于实现数字电路模块&#xff0c;用户可对FPGA…

Codeforces Round #666 (Div. 1) A. Multiples of Length

Problem - A - Codeforces翻译&#xff1a; 您将得到一个由&#x1d45b;个整数组成的数组&#x1d44e;。 你想要让&#x1d44e;的所有元素都等于零&#xff0c;只需执行以下操作三次: 选择一个段&#xff0c;对于这个段中的每一个数字&#xff0c;我们可以给它加上&#…

后疫情时代语音机器人和大数据的发展前景

语音机器人可以通过自动化流程和提供快速、准确的信息来帮助企业降低成本、增加效率。具体来说&#xff0c;企业可以使用语音机器人来完成以下任务&#xff1a; 客户服务&#xff1a;语音机器人可以自动处理客户查询和请求&#xff0c;从而节省人力成本。数据录入&#xff1a;…

Mask R-CNN论文讲解

目录&#xff1a;Mask R-CNN论文理解一、摘要二、介绍三、Mask R-CNN四、RoIAlign五、Network Architecture六、训练一、摘要 论文提出了一个概念上简单、灵活和通用的对象实例分割框架。有效地检测图像中的对象&#xff0c;同时为每个实例生成高质量的分割掩码。 方法被称为…

Python量化交易06——Fama-French三因子模型(Rmt,SMB,HML)

参考书目:深入浅出Python量化交易实战 本次带来的是著名的获得了诺贝尔奖的三因子模型。 因子模型介绍 Fama和French从可以解释股票收益率的众多因素中提取出了三个重要的影响因子&#xff0c;即市场风险溢酬因子、市值因子和账面市值比因子B/M Ratio&#xff0c;仿照CAPM模型…

测试用例能带来什么

通过测试用例&#xff0c;我们都能获得些什么呢? 1、测试团队的质量判断。例如&#xff0c;测试用例的覆盖率。我们只需要去把所有的valid的功能bug去做一个分析&#xff0c;用所有在测试用例覆盖范围之外的bug数/总bug数&#xff0c;就可以作为测试用例覆盖率使用。一个良好的…

【css】深入解析CSS (4)网格布局

设置为display: grid的元素成为一个网格容器&#xff08;grid container&#xff09;。它的子元素则变成网格元素&#xff08;grid items&#xff09;。 1.网格的组成部分&#xff1a; grid-template-columns和grid-template-rows定义了网格轨道 grid-template-columns:1fr 1f…

STM32/51单片机实训day4——RFID工作原理(一)理论

目录 一、RFID的定义 二、RFID的起源和发展 三、RFID的组成 3.1 标签 3.2 读写器 3.3 天线 四、RFID系统分类 4.1 根据标签的供电方式 4.2 根据工作频率 五、RFID系统工作原理 5.1 读写器 5.2 标签 5.3 中间件 内 容&#xff1a;能够读取RFID卡S50的ID——编程…

如何利用 xUnit 框架对测试用例进行维护?

1、xUnit 是什么 先看 Wikipedia 上的解释&#xff1a; xUnit 是一系列测试框架的统称&#xff0c;最开始来源于一个叫做 Smalltalk 的 SUnit 框架&#xff0c;现在各种面向对象的语言&#xff0c;如 Java、Python 的鼻祖就是 Smalltalk&#xff0c;后来这些语言都借助了 Suni…

Win10 开机突然蓝屏错误代码0xc0000001安全模式也进不了,不用重装系统怎么修复?(已解决)

环境: Win 10专业版 HP480G7 问题描述: Win10 开机突然蓝屏错误代码0xc0000001,前一天好好的,F8安全模式也进不了,不用重装系统怎么修复? 解决方案: 方法一 1.重启F8进入里面的安全模式(本案例进不了) 方法二 (解决本案例) 1.使用系统安装U盘,需提前做好…

力扣(LeetCode)220. 存在重复元素 III(C++)

滑动窗口有序集合 维护滑动窗口&#xff0c;向右扩大右窗口&#xff0c;新数加入有序集合&#xff0c;题目要求abs(nums[i] - nums[j]) < t &#xff0c;找两数之差的绝对值小于t&#xff0c;相当于在窗口里找大小尽可能接近的两个数&#xff0c;固定其中一个数(新数)&…

进程优先级环境变量进程地址空间

目录 一、进程优先级 1、概念 2、查看 3、其他概念 二、环境变量 1、基本概念 2、常见环境变量 3、查看环境变量的方法 4、和环境变量相关的命令 5、环境变量的组织方式 6、通过系统调用获取或设置环境变量 三、程序地址空间 一、进程优先级 1、概念 cpu资源分配的…

C++优先队列:priority_queue(即时排序队列)

今天我们来讲一下C中对于排序很好的用的东西&#xff1a;优先队列&#xff1a;priority_queue 既然是队列那么先要包含头文件#include <queue>, 它和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队 优先队列具有队列的所有特性&am…

数据结构---二叉树的各种遍历算法

&#xff08;一&#xff09;基础知识 如图遍历该树&#xff0c;常见有四种方法&#xff1a; 先根遍历&#xff1a;即先序遍历(Pre-order)&#xff0c;按照根左右的顺序沿一定路径经过路径上所有的结点。在二叉树中&#xff0c;先根后左再右。巧记&#xff1a;根左右。 以标准…

Redis 主从复制实现

1. 前言 今天从实用的角度来分析下 服务器间的主从部署&#xff0c;以及主从复制备份 2. 配置 一个服务器不同的端口代表不同的Redis实例端口6379 表示一台Redis主节点端口6380 表示一台Redis从节点&#xff0c;主节点的端口是6379端口6381 表示一台Redis从节点&#xff0c;主…

Type-challenges:00009-medium-deepReadonly

Implement a generic DeepReadonly<T> which make every parameter of an object - and its sub-objects recursively - readonly. https://github.com/TIMPICKLE/type-challenges/blob/main/questions/00009-medium-deep-readonly/README.md 虽然是medium&#xff0c;但…

图论(2)单源最短路的综合应用

活动 - AcWing 1.acwing1135 从自己家出发摆放其他亲戚&#xff0c;拜访顺序任意。 枚举所有摆放顺序求最小值即可。因此需要每个亲戚家到其他亲戚家的最短路。分别跑出来即可 #include<iostream> #include<algorithm> #include<cstring> #include<que…

pytorch批量计算数据集的均值和方差

from torchvision.transforms import ToTensor#用于把图片转化为张量 import numpy as np#用于将张量转化为数组&#xff0c;进行除法 from torchvision.datasets import ImageFolder#用于导入图片数据集means [0,0,0] std [0,0,0]#初始化均值和方差 transformToTensor()#可将…

UIVM项目验证—数据多通道整形器(MCDF)

1、项目介绍-MCDF MCDF(Multi-Channel Data Formatter)多通道数据整形器将上行多个通道数据存入FIFO&#xff0c;经过Arbiter仲裁&#xff0c;完成指定通道的数据打包&#xff0c;寄存器可以控制各个通道的开关、优先级以及数据包长度。 2、设计描述 CDF设计结构描述如下所示…

红队隧道应用篇之SSH端口转发突破内网(六)

前言 什么是SSH隧道 SSH隧道是使用SSH协议连接两台计算机之间的通道。它使用密钥加密数据传输&#xff0c;并允许计算机之间的安全连接。 通常&#xff0c;SSH隧道用于通过不安全的网络&#xff08;例如互联网&#xff09;连接到远程服务器。隧道提供了一种安全的方法来访问…