软件构造(4-8讲,下半)

软件构造(4-8讲,下半)

6. Object-Oriented Programming (OOP)
Interface接口
  • 接口可以实现静态方法,使用 static 关键字。通过static关键字可以实现静态工厂方法,从而将接口的实现类封装,实现对外信息隐藏。
  • 接口中也允许使用 default 关键字来定义并实现实例方法,这个应用有点类似于抽象类的功能。
  • 通过default方法,在接口中统一实现某些功能,无需在各个类中重复实现它。
继承和重写
  • **严格继承:**子类只能添加新方法,无法重写超类中的方法。原因:父类中的方法使用了final关键字限定。

  • **重写:**子类的方法覆盖了父类的方法。重写的方法应该与父类方法有相同的签名,只有这样编译器才会判定为重写的方法。使用@Override annotation强制检查是否重写了超类中的方法。

  • 在子类中如果想调用被重写的父类的方法,可以使用super.method()。

  • 如果是在构造方法中调用父类的构造方法,则必须在构造方法的第一行调用super()。

多态
  • 多态是继封装、继承之后,面向对象的第三大特性。

  • Java作为面向对象的语言,可以描述一个事物的多种形态。如Student类继承了Person类,那么一个Student的对象便既是Student,又是Person。多态体现为父类引用变量可以指向子类对象。前提条件:必须有子父类关系。

  • 定义格式:父类类型 变量名=new 子类类型();

  • 三种多态:特殊多态、参数化多态、子类型多态

    3.多态体现为父类引用变量可以指向子类对象

    4.前提条件:必须有子父类关系。

特殊多态:功能重载

重载:多个方法具有同样的名字,但有不同的参数列表或返回值类型。参数列表必须不同,返回值类型、可见性、异常均为可以相同也可不同。重载不仅可以发生在类内,也可发生在父类与子类之间。

父类与子类之间发生重载的例子如下。这两个情况都不能编译成功,以为无论是a还是h,他们的运行时类型都是Animal,而不是通过new创建的具体类型。

class Animal{
    public void eat(){...}
}
class Horse{
    public void eat(){...}
    public void eat(String food){...}
}
//两种不能通过编译的情况
Animal a = new Animal();
a.eat("Apple");
Animal h = new Horse();
h.eat("Apple");

参数化多态:泛型

使用泛型参数代替具体的类型。作为一个泛型接口,当实现的时候可以实现一个具有具体类型的子类型,也可以实现一个具有泛型接口的实现类。泛型是jdk5才引进的,泛型其实指得就是参数化类型,使得代码可以适应多种类型。像容器,List< T >,大量使用了泛型,它的主要目的之一就是用来指定容器要持有什么类型的对象。

通配符?,只在使用泛型的时候出现,不能在定义中出现。

子类型多态

终极目的:不同类型的对象可以统一处理而无需区分。

遵循的设计原则:LSP

LSP:子类可以扩展父类的功能,但不能改变父类原有的功能;子类可以实现父的抽象方法,但不能覆盖父类的非抽象方法。(下文还有)

理解:只要父类能出现的地方,子类就可以出现,并且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但反之,未要求。

7. 等价性equals()==

等价性是基于等价关系的,满足自反、对称、传递三个性质,它的空间意义是:如果R中的多个值都对应于A中的同一个值,那么这些R值都应该是等价的。

  • 引用等价性:使用==判断地址是否相同作为判断是否等价的依据。对基本数据类型,必须使用这种办法判断是否相等。

  • 对象等价性:使用equals()方法判断两个对象是否相同法作为判断是否等价的依据,对于对象类型,使用这种办法来判断对象是否等价,如果只用==则是在判断两个对象的ID(内存里的同一空间)是否相等。

8.LSP

子类重写父类的方法应该满足的条件:

编译器在静态类型检查时强制满足的条件

子类型可以增加方法,但不可删除
子类型需要实现抽象类型中的所有未实现方法
子类型中重写的方法返回值必须与父类相同或符合co-variance(协变)
子类型中重写的方法必须使用同样类型的参数或者符合contra-variance(逆变)的参数
子类型中重写的方法不能抛出额外的异常

还应该满足的条件

更强的不变量 (RI)
更弱的前置条件
更强的后置条件

9.协变

关于返回值的类型,应该保持不变或者变得更具体,也就是与派生的方向一致。

所抛出的异常的类型也是如此。

class T {
	Object a() {}
    void b() throws Throwable {}
}
class S extends T {
	@Override //返回值从Object协变成了String,这是符合重写的语法的
	String a() {}
    @Override //抛出的异常从Throwable协变成了IOException,这也是符合重写的语法的
	void b() throws IOException {}	
}

10. 逆变

关于参数的类型,应该保持不变或者变得更抽象,也就是与派生的方向相反。

class T {
	void c(String s) {}
}
class S extends T {
	@Override //虽然按照LSP这是合法的,但是在java语法中,不当作override,而是overload
	void c(Object s) {}
}

11. 委派

1.Dependency:依赖关系,临时性的delegation。把被delegation的对象以参数方式传入。只有在需要的时候才建立与被委派类的联系,而当方法结束的时候这种关系也就随之断开了。

//如果要让鸭子用其他方式叫(或飞)只需更换new的q(f)的类型即可
Flyable f = new FlyWithWings();	//使用翅膀飞行的飞行方式
Quackable q = new Quack();	//鸭叫声的叫声
Duck d = new Duck(); //一只鸭子
d.fly(f); //让鸭子飞
d.quack(q);	//让鸭子叫

class Duck {
	//no field to keep Flyable object
	public void fly(Flyable f) { f.fly(); } //让这个鸭子以f的方式飞
   public void quack(Quackable q) { q.quack() }; //让鸭子以q的方式叫
}

2.Association:关联关系,永久性的delegation。被delegation的对象保存在rep中,该对象的类型被永久的与此ADT绑定在了一起。

//法一:在构造方法中传入参数绑定
Flyable f = new FlyWithWings();
Duck d = new Duck(f);
d.fly();
class Duck {
	Flyable f; //这个必须由构造方法传入参数绑定
	public Duck(Flyable f) { this.f = f; }
   public void fly(){ f.fly(); }
}
//法二:在rep或构造方法中直接写死
Duck d = new Duck();
d.fly();
class Duck {
   //这两种实现方式的效果是相同的
	Flyable f = new FlyWithWings(); //写死在rep中
	public Duck() { f = new FlyWithWings(); } //写死在构造方法中
	public void fly(){ f.fly(); }
}

3.Composition: 更强的association,但难以变化。也就是Association中的法二。

4.Aggregation: 更弱的association,可动态变化。也就是Association中的法一。

12.框架
  • 黑盒框架:通过实现特定接口进行框架扩展,采用的是delegation机制达到这种目的,通常采用的设计模式是策略模式(Strategy)和观察者模式(Observer)
  • 白盒框架:通过继承和重写实现功能的扩展,通常的设计模式是模板模式(Template Method)。

白盒框架所执行的是框架所写好的代码,只有通过override其方法来实现新的功能,客户端启动的的是第三方开发者派生的子类型。黑盒框架并不是这样,黑盒所预留的是一个接口,在框架中只调用接口中的方法,而接口中方法的实现就依据派生出的子类型的不同而不同,它的客户端启动的就是框架本身。

白盒:

public abstract class Application extends JFrame {
    //这些抽象方法就是为了实现不同的部分而设计的
	abstract protected String getApplicationTitle();
	abstract protected String getButtonText();
	abstract protected String getInitialText();
	abstract protected void buttonclicked();
	private JTextField textField;
	public Application() {
		JPanel contentPane = new JPanel(new borderLayout());
		contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED))
		JButton button = new JButton();
        button.setText(getButtonText());
        contentPane.add(button, borderLayout.EAST);
        textField = new JTextField("");
        textField.setText(getInitialText());
        textField.setPreferredsize(new Dimension(200, 20));
        contentPane.add(textField, BorderLayout.WEST);
        button.addActionListener((e)->{ buttonclicked(); });
        this.setContentPane(contentPane);
        this.pack();
        this.setTitle(getApplicationTitle());
        ...
    }
}
//使用
public class Calculator extends Application {
    //重写了框架中的四个抽象方法
	protected String getApplicationTitle() { return "My Great Calculator"; }
    protected String getButtonText() { return "calculate"; }
    protected String getInititalText() { return "(10-3)*6"; }
    protected void buttonClicked() {
        JOptionPane.showMessageDialog(this, "the result of " + getInput() + "is" + calculate(getInput()));
    }
	private String calculate(String text) {...}
}

黑盒:

public class Application extends JFrame {
	private JTextField textField;
	private Plugin plugin;
	public Application() { }
	protected void init(Plugin p) {
		p.setApplication(this);
		this.plugin = p;
		JPanel contentPane = new JPanel(new BorderLayout());
        contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));
        JButton button = new JButton();
        button.setText(plugin != null ? plugin.getButtonText() : "ok");
        contentPane.add(button, BorderLayout.EAST);
        textField = new JTextField("");
        if (plugin != null) textField.setText(plugin.getInititalText());
        textField.setPreferredSize(new Dimension(200, 20));
        contentPane.add(textField, BorderLayout.WEST);
        if (plugin != null) button.addActionListener((e) -> { plugin.buttonClicked(); });
        this.setContentPane(contentPane);
        ...
    }
    public String getInput() { return textField.getText(); }
}
public interface Plugin {
    public String getApplicationTitle();
    public String getButtonText();
    public String getInititalText();
    public void buttonClicked();
    public void setApplication(Application app);
}
//使用,实现Plugin接口
public class CalcPlugin implements Plugin {
    private Application app;
    public void setApplication(Application app) { this.app = app; }
    public String getButtonText() { return "calculate"; }
    public String getInititalText() { return "10/2+6"; }
    public void buttonClicked() {
        JOptionPane.showMessageDiaLog(null, "The result of" + application.getInput() + "is" + calculate(application.getInput()));
    }
    public String getApplicationTitle() { return "My Great Calculator"; }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于YOLOv9实现工业布匹缺陷(破洞、污渍)检测系统python源码+详细运行教程+训练好的模型+评估 【使用教程】 一、环境配置 1、建议下载anaconda和pycharm 在anaconda中配置好环境,然后直接导入到pycharm中,在pycharm中运行项目 anaconda和pycharm安装及环境配置参考网上博客,有很多博主介绍 2、在anacodna中安装requirements.txt中的软件包 命令为:pip install -r requirements.txt 或者改成清华源后再执行以上命令,这样安装要快一些 软件包都安装成功后才算成功 3、安装好软件包后,把anaconda中对应的python导入到pycharm中即可(不难,参考网上博客) 二、环境配置好后,开始训练(也可以训练自己数据集) 1、数据集准备 需要准备yolo格式的目标检测数据集,如果不清楚yolo数据集格式,或者有其他数据训练需求,请看博主yolo格式各种数据集集合链接:https://blog.csdn.net/DeepLearning_/article/details/127276492 里面涵盖了上百种yolo数据集,且在不断更新,基本都是实际项目使用。来自于网上收集、实际场景采集制作等,自己使用labelimg标注工具标注的。数据集质量绝对有保证! 本项目所使用的数据集,见csdn该资源下载页面中的介绍栏,里面有对应的下载链接,下载后可直接使用。 2、数据准备好,开始修改配置文件 参考代码中data文件夹下的banana_ripe.yaml,可以自己新建一个不同名称的yaml文件 train:训练集的图片路径 val:验证集的图片路径 names: 0: very-ripe 类别1 1: immature 类别2 2: mid-ripe 类别3 格式按照banana_ripe.yaml照葫芦画瓢就行,不需要过多参考网上的 3、修改train_dual.py中的配置参数,开始训练模型 方式一: 修改点: a.--weights参数,填入'yolov9-s.pt',博主训练的是yolov9-s,根据自己需求可自定义 b.--cfg参数,填入 models/detect/yolov9-c.yaml c.--data参数,填入data/banana_ripe.yaml,可自定义自己的yaml路径 d.--hyp参数,填入hyp.scratch-high.yaml e.--epochs参数,填入100或者200都行,根据自己的数据集可改 f.--batch-size参数,根据自己的电脑性能(显存大小)自定义修改 g.--device参数,一张显卡的话,就填0。没显卡,使用cpu训练,就填cpu h.--close-mosaic参数,填入15 以上修改好,直接pycharm中运行train_dual.py开始训练 方式二: 命令行方式,在pycharm中的终端窗口输入如下命令,可根据自己情况修改参数 官方示例:python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 训练完会在runs/train文件下生成对应的训练文件及模型,后续测试可以拿来用。 三、测试 1、训练完,测试 修改detect_dual.py中的参数 --weights,改成上面训练得到的best.pt对应的路径 --source,需要测试的数据图片存放的位置,代码中的test_imgs --conf-thres,置信度阈值,自定义修改 --iou-thres,iou阈值,自定义修改 其他默认即可 pycharm中运行detect_dual.py 在runs/detect文件夹下存放检测结果图片或者视频 【特别说明】 *项目内容完全原创,请勿对项目进行外传,或者进行违法等商业行为! 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值