为什么子类不能访问基类的private成员?为什么要这样设计? .

  看到很多朋友提问“为什么子类不能访问基类的private成员”?随后看到很多朋友回答“这是规范”“这是封装的特性”类似这样的回答。我觉得大家都是对的。但是有时候您需要关注提问的重点在于why?为什么Java要这样设计private?或者是Object Oriented为啥要这样设计这样的机制?

 

  • 封装性:首先,private成员具有良好的封装性(encapsulation)。这个性质对于良好的设计来说是个重要的要素。因为良好的封装性会减小耦合的。服务代码可以定义public函数给客户代码。这样一来客户代码可以和服务代码并行开发。更重要的是,如果修改服务代码的内部实现也不需要改动客户代码。

 

  • 子类也是客户代码:对于客户代码的理解最直接的就是调用这个类的代码,这个很好理解。更深入的理解就可以把客户代码延伸到这个类的子类。从这一点来说子类就是基类的客户代码。你定义了一个class,在里面写了些通用的方法,甚至申明了abstract方法要求别人来继承。这个时候基类里面的protect成员就是对外的API,因为这些方法对子类来说是可见的,你不能随意改动。这个时候如果这个成员是public或者protected就可能造成麻烦。对于API来说你不能随意改动。你能设想JDK里面的有些类的API改动的情况吗?至少我会抓狂的:)

 

  • 访问权限扩大原则:延伸话题来说,还有就是Java对override的时候访问权限的限制。大家都知道Java的访问权限从小到大是:private-> default->  protected-> public。如果要override一个基类里面的方法,那么子类的这个方法的权限不能比被override的函数权限小。这样就导致一个隐性的问题:如果你的基类有public方法,那么它的子类里面都有这个方法的public属性。你不能把基类的这个方法private化。换句话说一旦定义了public函数,它的子类都要维护这个public方法。所以就算是方法也要小心地把它设为public。

 

  当然如果这个基类到最终的子类都是你维护,或者这个类本身就是个非public的类,那么原则可以放宽。

 

  顺便说一下,Eclipse有自动生成标准get/set函数的功能,所以生成get/set是很容易的事情,不要为了方便把成员都变成public。

 

  譬如写了个基类Base,然后有人继承了Base:

  1. public class Base {  
  2.    public String[] data;  
  3. }  
  4. class Sub extends Base{  
  5.     public void show(){  
  6.         System.out.println(Arrays.toString(this.getData()));  
  7.     }  
  8. }  
 

可是有一天你发觉用ArrayList更好,你就把Base改成:

  1. public class Base {  
  2.    //public String[] data;   
  3.    public ArrayList data;  
  4. }  
 

然后所有Base的子类都无法编译,直接调用到子类data域的类也无法编译。这就是噩梦,客户端程序员会用眼光追杀你:)

回过头来想,如果当初Base的data域是private,由get/set来访问,那么你可以轻松的修改Base, 子类无需改动:

  1. public class Base {  
  2.     //private String[] data;   
  3.     private ArrayList<String> data;  
  4.       
  5.     public String[] getData() {  
  6.         return  (String[]) data.toArray();  
  7.     }  
  8.       
  9.     public void setData(String[] data) {  
  10.         this.data = new ArrayList<String>(Arrays.asList(data));  
  11.     }  
  12. }  

 

作者:卢声远michaellufhl@yahoo.com.cn

在实现消息卡片基类 `BasicMessageCard` 时,需要定义通用的属性和方法,以便子类(如 `TPGuardMessageCardView` 和 `NewMessageCardView`)能够复用基础逻辑,同时支持个性化扩展。以下是基类的核心实现建议: --- ### **`BasicMessageCard` 基类实现** ```swift import Cocoa class BasicMessageCard: NSView { // MARK: - 通用属性 var message: Any? { didSet { setupText() // 消息更新时刷新UI } } // MARK: - 子视图(需在子类中具体实现) private(set) var iconView = NSImageView() private(set) var titleLabel = TPBLabel() private(set) var subTitleLabel = TPBLabel() private(set) var timeLabel = TPBLabel() private(set) var actionButtons: [NSButton] = [] // 操作按钮(如接受/拒绝) private(set) var closeButton = TPBButton.iconButton(with: .closeButton) // MARK: - 初始化 override init(frame frameRect: NSRect) { super.init(frame: frameRect) setupSubviews() makeConstraints() bindActions() setupStyle() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - 需子类重写的方法 /// 设置子视图(由子类实现具体布局) func setupSubviews() { // 基础子视图(子类可添加额外视图) addSubview(iconView) addSubview(titleLabel) addSubview(subTitleLabel) addSubview(timeLabel) addSubview(closeButton) } /// 布局约束(由子类实现具体约束) func makeConstraints() { // 基础约束(子类可扩展) closeButton.snp.makeConstraints { make in make.top.equalToSuperview().offset(12) make.trailing.equalToSuperview().offset(-16) make.size.equalTo(14) } } /// 绑定按钮事件(由子类实现具体逻辑) func bindActions() { closeButton.onClickCallback = { [weak self] in self?.handleClose() } } /// 更新文本内容(由子类实现具体文本逻辑) func setupText() { // 子类需根据 `message` 型更新UI } /// 设置样式(圆角、背景色等) func setupStyle() { wantsLayer = true layer?.cornerRadius = 8.0 layer?.backgroundColor = NSColor.tpBackground.cgColor layer?.borderWidth = 1.0 layer?.borderColor = NSColor.tpNotifyBorder.cgColor } // MARK: - 公共方法 /// 处理关闭事件(可由子类重写) func handleClose() { removeFromSuperview() // 默认行为:从父视图移除 } /// 添加操作按钮(如“接受”“拒绝”) func addActionButton(_ button: NSButton) { actionButtons.append(button) addSubview(button) } } ``` --- ### **子类实现示例** #### 1. 原有卡片(`TPGuardMessageCardView`)改造: ```swift class TPGuardMessageCardView: BasicMessageCard { private var applyButton = TPBButton() private var cancelButton = TPBButton() override func setupSubviews() { super.setupSubviews() addActionButton(applyButton) addActionButton(cancelButton) } override func makeConstraints() { super.makeConstraints() iconView.snp.makeConstraints { make in make.leading.equalToSuperview().offset(10) make.top.equalToSuperview().offset(28) make.size.equalTo(52) } titleLabel.snp.makeConstraints { make in make.leading.equalTo(iconView.snp.trailing).offset(8) make.top.equalToSuperview().offset(18) } applyButton.snp.makeConstraints { make in make.leading.equalTo(iconView.snp.trailing).offset(8) make.bottom.equalToSuperview().offset(-12) make.size.equalTo(NSSize(width: 77, height: 32)) } } override func bindActions() { super.bindActions() applyButton.onClickCallback = { [weak self] in if let message = self?.message as? TPGuardDeviceShareMessage { TPGuardMessageManager.shard.acceptShare(shareMesssage: message) } } } override func setupText() { guard let message = message as? TPGuardDeviceShareMessage else { return } titleLabel.text = message.content.replacingOccurrences(of: "null", with: message.sharerUserName) // 其他文本设置... } } ``` #### 2. 新消息卡片(`NewMessageCardView`)示例: ```swift class NewMessageCardView: BasicMessageCard { private var detailButton = TPBButton() override func setupSubviews() { super.setupSubviews() addActionButton(detailButton) } override func setupText() { guard let message = message as? NewMessageType else { return } titleLabel.text = message.title subTitleLabel.text = message.detail } } ``` --- ### **基类设计的关键点** 1. **通用属性**: - `message` 作为数据源,支持任意型(通过子类型转换)。 - 预定义常用子视图(如 `iconView`、`titleLabel`),避免子类重复创建。 2. **生命周期方法**: - `setupSubviews()`、`makeConstraints()`、`bindActions()` 由子类实现具体逻辑,基类仅定义框架。 - `setupText()` 在 `message` 更新时自动调用。 3. **扩展性**: - 通过 `addActionButton()` 动态添加操作按钮。 - 子类可覆盖 `handleClose()` 自定义关闭行为。 4. **样式统一**: - 基类预设圆角、边框等样式,子类可通过 `setupStyle()` 调整。 --- ### **相关问题** 1. 如何确保基类的 `message` 属性在子类型安全? 2. 基类是否需要抽象按钮的公共行为(如统一动画效果)? 3. 如何处理同消息卡片的动态高度? 4. 基类是否需要提供默认的空状态(`message == nil`)UI? 5. 子类如何覆盖基类的样式(如边框颜色)而影响其他子类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值