关于面向对象的一个问题

u010233287 2017-09-15 10:51:16
现有类Father,里面提供属性Name,要求如下:
① 类BigSon继承Father,而且其Name属性需要对外提供get、set方法
② 类SmallSon继承Father,而且其Name属性只能对外提供get方法
③ 在初始化对象时,必须按如下:
Father bs = new BigSon();
Father ss = new SmallSon();

在实现过程中遇到下面的问题:

1)将Father类里面的属性Name按如下实现:
public string Name { get; }
这样BigSon不能提供set方法

2)将Father类里面的属性Name按如下实现:
public string Name { get; set; }
这样SmallSon不能去掉set方法

3)将Father类里面的属性Name按如下实现:
public string Name { get; }
然后SmallSon类中覆盖Father里面的Name属性,
这样能够去掉set方法,可是ss.Name访问的还是Father类的Name属性

4)定义一个接口INameable, 里面包含属性:string Name { get; }
然后BigSon实现时提供get和set方法,SmallSon实现时只提供get方法。
可是这样一来,bs和ss访问Name时还必须先转换为接口类型

我的问题是:
有没有一种好的解决方法可以解决这个问题?
...全文
696 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
cheng2005 2017-09-16
  • 打赏
  • 举报
回复
你的子类和父类根本就不是一样的东西。 你的父类假设“人类”都有两支手臂(左臂和右臂),两条腿(左腿和右腿)。但是你的子类,则可能出现缺胳膊少腿的情况,这种情况下,要么在运行时抛错(异常),要么你的父类就要重新设计。 方法1,砍掉胳膊和腿。 class Person,然后最做接口 I左臂,I右臂,I左腿,I右腿,去交给子类去集成。class A:Person,I左臂,I右臂 方法2,父类要包含胳膊和腿,class Person里有属性 Get左臂,Get右臂,Get左腿,Get右腿。子类只要实现Get方法即可。没有的返回null,正确处理就OK了。
秋的红果实 2017-09-15
  • 打赏
  • 举报
回复

class Father
{
    protected string Name;
}
class BigSon:Father
{
    public string name
    {
        set { Name = value; }
        get { return Name; }
    }
}
class smallSon:Father
{
    public string name
    {
        get { return Name; }
    }

    public smallSon(string pName)
    {
        Name = pName;
    }
}

//使用
BigSon bs = new BigSon();
bs.name = "Mr.zhang";
MessageBox.Show(bs.name);

smallSon ss = new smallSon("Mr.Li");
MessageBox.Show("Name is:"+ss.name);

很想知道,lz用 Father bs = new BigSon(); Father ss = new SmallSon(); 类型用Father是想达到什么效果? 类的设计,从需求中抽取共同的东西,作为父类,个性化的东西放到子类具体实现
白衣如花 2017-09-15
  • 打赏
  • 举报
回复
大佬讲了设计上的不合理 我说说这个功能的实现吧 Father {protected string name; } BigSon:Father{public Name {get {return name;} set {name = value;}}} SmallSon:Father{public Name {get {return name;}}}
  • 打赏
  • 举报
回复
程序是死的、人是活的。技术永远都是最低级的东西,需求和实用才是目的。 因此当你遇到编程设计中总是感觉到“反动”,你首先考虑是不是别人刁难你,或者是不是自己出现了对未来系统扩展设计方向跑偏了的问题。 总之要保持面向对象系统设计的接口和原则。如果遇到完全无法面向对象设计,那么可以考虑就不采用面向对象系统设计方法,甚至放弃编程。
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 3 楼 sp1234 的回复:
这个问题引申开来,其实背后是一个系统分析问题,而不是编程实现问题。就是,有些人为了少些几行代码而面向对象。这就会产生错误的、诡异的代码。 比如说,假设我们设计一个“矩形”作为父类,它可以设置长和宽,可以求得“面积”。假设“正方形”是从它继承的,也可以设置长和宽(只不过设置宽是自动也就设置了长,设置长时也就自动设置了宽),那么就遇到一个尴尬的事情,就是过去针对矩形的一些测试用例用在正方形上就不对了。这个时候有两种选择,一种就是放弃这种继承,重新分析和设计业务领域模型;另一种就是放弃过去对于矩形的不切实际的测试观念,而是承认“通用的矩形”也会自动改变长和宽而并不总是保证跟客户录入的值一致。 说白了,就是遇到那种“在子类中故意给父类的定义找麻烦”的思路时,这本身就越来愈不符合面向对象系统分析和设计方法,这时候就可能越来越具有破坏性,这时候可能就不适合面向对象系统设计。真正好的继承和多态的设计,是子类顺利地、不怀疑地能够在父类的基础上进行扩展和增强。 遇到那种自以为“不一样”、总想改变父类规则的子类,我们要知道它其实是假的面向对象,其实造成系统顺利分析的“反动”结果。
谢谢你的耐心解答,感觉学到了好多
  • 打赏
  • 举报
回复
这个问题引申开来,其实背后是一个系统分析问题,而不是编程实现问题。就是,有些人为了少些几行代码而面向对象。这就会产生错误的、诡异的代码。 比如说,假设我们设计一个“矩形”作为父类,它可以设置长和宽,可以求得“面积”。假设“正方形”是从它继承的,也可以设置长和宽(只不过设置宽是自动也就设置了长,设置长时也就自动设置了宽),那么就遇到一个尴尬的事情,就是过去针对矩形的一些测试用例用在正方形上就不对了。这个时候有两种选择,一种就是放弃这种继承,重新分析和设计业务领域模型;另一种就是放弃过去对于矩形的不切实际的测试观念,而是承认“通用的矩形”也会自动改变长和宽而并不总是保证跟客户录入的值一致。 说白了,就是遇到那种“在子类中故意给父类的定义找麻烦”的思路时,这本身就越来愈不符合面向对象系统分析和设计方法,这时候就可能越来越具有破坏性,这时候可能就不适合面向对象系统设计。真正好的继承和多态的设计,是子类顺利地、不怀疑地能够在父类的基础上进行扩展和增强。 遇到那种自以为“不一样”、总想改变父类规则的子类,我们要知道它其实是假的面向对象,其实造成系统顺利分析的“反动”结果。
  • 打赏
  • 举报
回复
胡乱改变接口形式问题的话,这并不符合面向对象基本原则(不管是五大原则还是六大原则)。 所以,顶多来说,只能让运行时崩溃。也就是写
public class B: A
{
    public override string XXX
    {
        set
        {
            throw new Exception("不给你提供。");
         }
    ...............
这种形式。 如果连接口形式都不能兼容,那么还说什么面向对象设计和开发呢?
ilikeff8 2017-09-15
  • 打赏
  • 举报
回复
GetAccessors 可以查询某属性是否有get和set访问器,上面的代码中,由于Name在子类SmallSon中被重写了,导致查询Name访问器时,只有get访问器
ilikeff8 2017-09-15
  • 打赏
  • 举报
回复
你的设计很有问题,不过还是有办法实现你的要求的
        static void Main(string[] args)
        {
            Father bs = new BigSon();
            Father ss = new SmallSon();

            bs.Name = "BigSon";
            ss.Name = "SmallSon";
        }

        class Father
        {
            string name;
            public string Name
            {
                get
                {
                    return name;
                }
                set
                {
                    if (this.GetType().GetProperty(nameof(Name)).GetAccessors()?.Any(p => p.IsSpecialName && p.Name == "set_" + nameof(Name)) ?? false)
                    {
                        name = value;
                    }
                    else
                    {
                        throw new Exception("不支持");
                    }
                }
            }
        }

        class BigSon:Father
        {
        }

        class SmallSon : Father
        {
            new public string Name
            {
                get
                {
                    return base.Name;
                }
            }
        }
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 18 楼 hanjun0612 的回复:
[quote=引用 16 楼 u010233287 的回复:] class UserTwo : User { //使用override来重写的话,返回的就是子类本身的值了 //可是这样你的set也必须跟着重写,去不掉了 public override string Name { get { return "亚历山大"; } //安照#1大佬的说法,这里只能退而求其次的抛出一个未实现异常 set { throw new NotImplementedException(); } } }
如果一定要输出亚历山大, 那么就这样 User user1 = new UserOne(); user1.Name = "张三"; Console.WriteLine(user1.Name); //张三 Console.WriteLine(((UserOne)user1).Name); //尼古拉斯[/quote] O(∩_∩)O谢谢你的耐心,由于实际需求是User有非常多子类,得到的对象你不可能这样强制转换的,你可以帮我看看13楼的需求,不必纠结我上午表述不当的那个问题。再次感谢
正怒月神 2017-09-15
  • 打赏
  • 举报
回复
引用 16 楼 u010233287 的回复:
class UserTwo : User { //使用override来重写的话,返回的就是子类本身的值了 //可是这样你的set也必须跟着重写,去不掉了 public override string Name { get { return "亚历山大"; } //安照#1大佬的说法,这里只能退而求其次的抛出一个未实现异常 set { throw new NotImplementedException(); } } }
如果一定要输出亚历山大, 那么就这样 User user1 = new UserOne(); user1.Name = "张三"; Console.WriteLine(user1.Name); //张三 Console.WriteLine(((UserOne)user1).Name); //尼古拉斯
正怒月神 2017-09-15
  • 打赏
  • 举报
回复
哦,看你13楼需求,那我觉得是否开放color和Size的set方法,应该是子类的事情,而不是父类的事情。
哪用5,6#的方法就行了。父类只有字段,子类实现get;set;方法
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 9 楼 hanjun0612 的回复:
虽然违背了继承思想。 不过借用一下new关键字吧(虽然我不认为new关键字合理
        static void Main(string[] args)
        {
            User1 u1 = new User1() ;
            u1.id = 1;        //这里会报错,u1.id只读

            User u = new User();
            u.id = 1;    //没问题

            User u2 = new User1();
            u2.id = 1;    //没问题

            Console.ReadLine();
        }
        

    public class User
    {
        public virtual int id { get; set; }
        public virtual string name { get; set; }
        public virtual string buyer { get; set; }
        public virtual string idArr { get; set; }

    }
public class User1:User
    {
        //补充一下,这个例子用 override 也可以
        public new int id { get; }
    }
我的真实需求在13楼,请大神帮忙看看指出设计的不合理指出,O(∩_∩)O谢谢
引用 15 楼 hanjun0612 的回复:
[quote=引用 12 楼 u010233287 的回复:] 你看我第三点说的,需要的是User u= new User1(); 然后你调用u.id你看看它是返回的User1的id吗
那基于你要的情况,用new就可以了啊。 我没有看出有什么问题。 [/quote]

        class Program
	{
		static void Main(string[] args)
		{
			User user1 = new UserOne();
			user1.Name = "张三";
			Console.WriteLine(user1.Name); // Output: 张三

			User user2 = new UserTwo();
			user2.Name = "李四";
			Console.WriteLine(user2.Name); // Output: 亚历山大

			Console.Read();
		}
	}
	class User
	{
		public virtual string Name { set; get; }
	}
	class UserOne : User
	{
		//使用new关键字的确可以去掉set,但是当用父类引用子类变量时
		//Name属性返回的还是父类该属性的值。
		public new string Name { get { return "尼古拉斯"; } }	
	}
	class UserTwo : User
	{
		//使用override来重写的话,返回的就是子类本身的值了
		//可是这样你的set也必须跟着重写,去不掉了
		public override string Name
		{
			get { return "亚历山大"; }
			//安照#1大佬的说法,这里只能退而求其次的抛出一个未实现异常
			set { throw new NotImplementedException(); }
		}
	}
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 3 楼 sp1234 的回复:
这个问题引申开来,其实背后是一个系统分析问题,而不是编程实现问题。就是,有些人为了少些几行代码而面向对象。这就会产生错误的、诡异的代码。 比如说,假设我们设计一个“矩形”作为父类,它可以设置长和宽,可以求得“面积”。假设“正方形”是从它继承的,也可以设置长和宽(只不过设置宽是自动也就设置了长,设置长时也就自动设置了宽),那么就遇到一个尴尬的事情,就是过去针对矩形的一些测试用例用在正方形上就不对了。这个时候有两种选择,一种就是放弃这种继承,重新分析和设计业务领域模型;另一种就是放弃过去对于矩形的不切实际的测试观念,而是承认“通用的矩形”也会自动改变长和宽而并不总是保证跟客户录入的值一致。 说白了,就是遇到那种“在子类中故意给父类的定义找麻烦”的思路时,这本身就越来愈不符合面向对象系统分析和设计方法,这时候就可能越来越具有破坏性,这时候可能就不适合面向对象系统设计。真正好的继承和多态的设计,是子类顺利地、不怀疑地能够在父类的基础上进行扩展和增强。 遇到那种自以为“不一样”、总想改变父类规则的子类,我们要知道它其实是假的面向对象,其实造成系统顺利分析的“反动”结果。
我的真实需求在13楼,请大神帮忙看看指出设计的不合理指出,O(∩_∩)O谢谢
u010233287 2017-09-15
  • 打赏
  • 举报
回复
我的真实需求是这样子的:

现有类Host和类View类,两者构成如下聚合关系


对于View类,它是一个抽象类,有很多的子类,而且子类与子类之间也是聚合的关系


为了简化Host类中的操作,我弄出了一个ViewRoot


由于RootView和View具有蛮多相同的属性和操作,因此提取了一个公共基类


在每个View的子类中包含一个Parent属性,而Parent的类型有的是RootView(直接加到RootView下的View),有的是View,因此我使用了ViewBase作为其类型。

RootView与View虽然有很多相同属性和操作,但是也有不一样的地方,比如RootView的Color、Size等属性不能够设置,而是固定好了的;而View子类里面的Color、Size可以用户设置。

这里的RootView和View就相当于上面的SmallSon和BigSon,而Color、Size就相当于Name。

基于此,才有了上午提到的那些问题。
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 11 楼 hanjun0612 的回复:
[quote=引用 10 楼 u010233287 的回复:] 这个不行,我在上面描述的第三点说到了。使用重写的话,你的set又去不掉
你用我的代码试试吧。 如果u.id=1赋值,编译器都不通过,提示只读。 我不清楚,你说的 set去不掉,是一个什么概念。 u.id只读了,不就相当于set没有了吗?[/quote] 你看我第三点说的,需要的是User u= new User1(); 然后你调用u.id你看看它是返回的User1的id吗
正怒月神 2017-09-15
  • 打赏
  • 举报
回复
引用 10 楼 u010233287 的回复:
这个不行,我在上面描述的第三点说到了。使用重写的话,你的set又去不掉
你用我的代码试试吧。 如果u.id=1赋值,编译器都不通过,提示只读。 我不清楚,你说的 set去不掉,是一个什么概念。 u.id只读了,不就相当于set没有了吗?
u010233287 2017-09-15
  • 打赏
  • 举报
回复
引用 9 楼 hanjun0612 的回复:
虽然违背了继承思想。 不过借用一下new关键字吧(虽然我不认为new关键字合理
        static void Main(string[] args)
        {
            User1 u1 = new User1() ;
            u1.id = 1;        //这里会报错,u1.id只读

            User u = new User();
            u.id = 1;    //没问题

            User u2 = new User1();
            u2.id = 1;    //没问题

            Console.ReadLine();
        }
        

    public class User
    {
        public virtual int id { get; set; }
        public virtual string name { get; set; }
        public virtual string buyer { get; set; }
        public virtual string idArr { get; set; }

    }
public class User1:User
    {
        //补充一下,这个例子用 override 也可以
        public new int id { get; }
    }
这个不行,我在上面描述的第三点说到了。使用重写的话,你的set又去不掉
正怒月神 2017-09-15
  • 打赏
  • 举报
回复
虽然违背了继承思想。
不过借用一下new关键字吧(虽然我不认为new关键字合理

        static void Main(string[] args)
{
User1 u1 = new User1() ;
u1.id = 1; //这里会报错,u1.id只读

User u = new User();
u.id = 1; //没问题

User u2 = new User1();
u2.id = 1; //没问题

Console.ReadLine();
}


public class User
{
public virtual int id { get; set; }
public virtual string name { get; set; }
public virtual string buyer { get; set; }
public virtual string idArr { get; set; }

}
public class User1:User
{
//补充一下,这个例子用 override 也可以
public new int id { get; }
}
正怒月神 2017-09-15
  • 打赏
  • 举报
回复
引用 3 楼 sp1234 的回复:
这个问题引申开来,其实背后是一个系统分析问题,而不是编程实现问题。就是,有些人为了少些几行代码而面向对象。这就会产生错误的、诡异的代码。 比如说,假设我们设计一个“矩形”作为父类,它可以设置长和宽,可以求得“面积”。假设“正方形”是从它继承的,也可以设置长和宽(只不过设置宽是自动也就设置了长,设置长时也就自动设置了宽),那么就遇到一个尴尬的事情,就是过去针对矩形的一些测试用例用在正方形上就不对了。这个时候有两种选择,一种就是放弃这种继承,重新分析和设计业务领域模型;另一种就是放弃过去对于矩形的不切实际的测试观念,而是承认“通用的矩形”也会自动改变长和宽而并不总是保证跟客户录入的值一致。 说白了,就是遇到那种“在子类中故意给父类的定义找麻烦”的思路时,这本身就越来愈不符合面向对象系统分析和设计方法,这时候就可能越来越具有破坏性,这时候可能就不适合面向对象系统设计。真正好的继承和多态的设计,是子类顺利地、不怀疑地能够在父类的基础上进行扩展和增强。 遇到那种自以为“不一样”、总想改变父类规则的子类,我们要知道它其实是假的面向对象,其实造成系统顺利分析的“反动”结果。
说白了,就是遇到那种“在子类中故意给父类的定义找麻烦”的思路 这句话很透彻。
第1章课程定位与教学案例综述. 1.1职业岗位能力需求分析 1.2课程设置和课程定位分析 1.3WebShop电子商城介绍 1.3.1电子商城需求分析 1.3.2电子商城系统设计 1.3.3电子商城数据库设计 1.4LibraryMIS图书管理系统介绍 1.4.1图书管理系统需求分析 1.4.2图书管理系统系统设计 1.4.3图书管理系统数据库设计 习题 第2章面向对象技术和建模基础 2.1面向对象方法 2.1.1面向对象方法的基本思想 2.1.2面向对象方法的发展 2.2面向对象的基本概念与特征 2.2.1面向对象的基本概念 2.2.2面向对象的主要特征 2.3面向对象分析 .2.3.1处理复杂问题的原则 2.3.200A方法的基本步骤 2.4面向对象设计 2.5面向对象实现 2.6面向对象方法的内涵 2.7软件建模概述 2.7.1软件建模的概念 2.7.2软件建模的用途 2.7.3软件建模的优点 习题 第3章UML简介 3.1UML的发展 3.1.1UML的发展历程 3.1.2理解UML建模 3.2UML的特点 3.3UML的结构 3.3.1UML的事物 3.3.2UML的关系 3.4UML的视图 3.4.1用例视图 3.4.2逻辑视图 3.4.3并发视图 3.4.4组件视图 3.4.5部署视图 3.5UML图形符号 3.5.1用例图 3.5.2类图 3.5.3对象图 3.5.4状态图 3.5.5活动图 3.5.6顺序图 3.5.7协作图 3.5.8组件图 3.5.9部署图 3.5.10UML 2.0新特性 3.6UML建模基本流程 习题 第4章UML建模工具简介 4.1常用UML建模工具 4.1.1 Rational Rose 4.1.2Enterprise Architect 4.1.3Together 4.1.4PowerDesigner 4.1.5 Visi0 4.1.6Tnffun Plat0 4.2Rational Rose安装与配置 4.2.1Rational Rose的运行环境 4.2.2Rational Rose的安装 4.2.3Rational Rose的配置 4.3使用Rational Rose建模 4.3.1Rational Rose主菜单 4.3.2Rational Rose的视图 4.3.3 Rational Rose建模的基本过程 习题 第5章需求建模 5.1用例模型概述 5.2用例图组成 5.2.1参与者 5.2.2系统 5.2.3用例 5.3识别和描述用例.. 5.3.1识别用例 5.3.2绘制WebShop电子商城用例图 5.3.3通过包对用例进行合理规划 5.3.4WebShop电子商城用例图(不含关系) 5.3.5用例描述 5.4用例间的关系 5.4.1泛化关系 5.4.2使用关系 5.4.3包含关系 5.4.4扩展关系 5.4.5关系小结 5.4.6WebShop电子商城用例图(含关系) 习题 第6章静态建模 6.1静态建模概述 6.2类图概述 6.3类图的基本组成 6.3.1类的概述 6.3.2绘制带属性的实体类 6.3.3绘制带操作的实体类 6.3.4绘制边界类图 6.3.5绘制控制类图 6.3.6UML中的类与语言中的类 6.4类之间的关系 6.4.1关联关系 6.4.2聚合关系 6.4.3组合关系 6.4.4泛化关系 6.4.5实现关系 6.4.6依赖关系 6.5对象图 6.5.1对象图概述 6.5.2对象图组成 6.5.3类图和对象图的比较 习题 第7章数据库建模 7.1PowerDesigner简介 7.2PowerDesigner安装和启动 7.2.1PowerDesigner的安装 7.2.2PowerDesigner的启动 7.3PowerDesigner概念数据模型 7.3.1概念数据模型概述 7.3.2PowerDesigner概念数据模型概述 7.4 PowerDesigner物理数据模型 习题 第8章动态建模 8.1动态建模概述 8.2状态图 8.2.1状态图概述 8.2.2状态图组成 8.2.3绘制员工下班回家状态图 8.3活动图 8.3.1活动图概述 8.3.2活动图组成 8.3.3绘制WebShop电子商城活动图 8.4活动图拾遗 8.4.1活动图与流程图的比较 8.4.2活动图与状态图的比较 8.5顺序图 8.5.1顺序图概述 8.5.2顺序图组成 8.5.3绘制WebShop电子商城顺序图 8.6协作图 8.6.1协作图概述 8.6.2协作图组成 8.6.3绘制WebShop电子商城协作图 8.7 顺序图拾遗 8.7.1 顺序图与协作图的比较 8.7.2 顺序图与协作图的互换 习题 第9章物理建模 9.1物理建模概述 9.1.1硬件 9.1.2软件 9.2组件图 9.2.1组件图概述 9.2.2组件图组成 9.2.3绘制WebShop电子商城组件图 9.3部署图 9.3.1部署图概述 9.3.2部署图组成 9.3.3绘制WebShop电子商城部署图 习题 第10章双向工程 10.1双向工程简介 10.2正向工程(生成Java代码) 10.3逆向工程 习题 第11章统一软件过程RUP 11.1RUP简介 11.2RUPT作流程 11.2.1业务建模 11.2.2需求 11.2.3分析设计 11.2.4实施 11.2.5测试 11.2.6部署 11.2.7配置与变更管理 11.2.8项目管理 11.2.9环境 11.3RUP迭代过程 11.3.1初始 11.3.2细化 11.3.3构造 11.3.4移交 11.3.5迭代计划示例(构造阶段) 习题 附录A综合实训 附录B Rational Rose2003主菜单 参考文献...

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧