Являются ли композиция и наследование одинаковыми?
Они не совпадают.
Композиция : позволяет группе объектов обрабатываться так же, как один экземпляр объекта. Цель композита состоит в том, чтобы «компоновать» объекты в древовидных структурах представлять целые иерархии
Inheritance : класс наследует поля и методы из все его суперклассы, прямые или косвенные. Подкласс может переопределять методы, которые он наследует, или он может скрыть поля или методы, которые он наследует.
Если я хочу реализовать шаблон композиции, как я могу это сделать на Java?
Статья в Википедии достаточно хороша для реализации составного шаблона в java.
Ключевые участники:
Компонент:
- Является абстракцией для всех компонентов, включая составные
- Объявляет интерфейс для объектов в композиция
Лист:
- Представляет листовые объекты в композиции
- Реализует все методы Component
Композит:
- Представляет составной компонент (компонент с дочерними элементами)
- Реализует методы манипулирования детьми
- Реализует все методы Component, обычно делегируя их своим детям
Пример кода для понимания Composite patter n:
import java.util.List; import java.util.ArrayList; interface Part{ public double getPrice(); public String getName(); } class Engine implements Part{ String name; double price; public Engine(String name,double price){ this.name = name; this.price = price; } public double getPrice(){ return price; } public String getName(){ return name; } } class Trunk implements Part{ String name; double price; public Trunk(String name,double price){ this.name = name; this.price = price; } public double getPrice(){ return price; } public String getName(){ return name; } } class Body implements Part{ String name; double price; public Body(String name,double price){ this.name = name; this.price = price; } public double getPrice(){ return price; } public String getName(){ return name; } } class Car implements Part{ List
parts; String name; public Car(String name){ this.name = name; parts = new ArrayList (); } public void addPart(Part part){ parts.add(part); } public String getName(){ return name; } public String getPartNames(){ StringBuilder sb = new StringBuilder(); for ( Part part: parts){ sb.append(part.getName()).append(" "); } return sb.toString(); } public double getPrice(){ double price = 0; for ( Part part: parts){ price += part.getPrice(); } return price; } } public class CompositeDemo{ public static void main(String args[]){ Part engine = new Engine("DiselEngine",15000); Part trunk = new Trunk("Trunk",10000); Part body = new Body("Body",12000); Car car = new Car("Innova"); car.addPart(engine); car.addPart(trunk); car.addPart(body); double price = car.getPrice(); System.out.println("Car name:"+car.getName()); System.out.println("Car parts:"+car.getPartNames()); System.out.println("Car price:"+car.getPrice()); } } выход:
Car name:Innova Car parts:DiselEngine Trunk Body Car price:37000.0
Объяснение:
- Часть - это лист
- Автомобиль содержит много частей
- В автомобиль добавлены запчасти автомобиля
- Цена Автомобиль = сумма (Цена каждой партии)
См. ниже вопрос о преимуществах и недостатках композиции и наследования.
Обновление: В Python 2.6 и новее подумайте, соответствует ли структура данных namedtuple
вашим потребностям:
>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object has no attribute 'c'
>>> s.d
['hi']
Альтернатива (исходное содержание ответа):
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
Затем вы можете использовать:
>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
Вот еще одна реализация:
class DictObj(object):
def __init__(self, d):
self.__dict__ = d
def dict_to_obj(d):
if isinstance(d, (list, tuple)): return map(dict_to_obj, d)
elif not isinstance(d, dict): return d
return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))
[Edit] Пропущен бит, касающийся также обработки словарей внутри списков, а не только других словарных статей. Добавлено исправление.
Вот еще один способ реализовать исходное предложение SilentGhost:
def dict2obj(d):
if isinstance(d, dict):
n = {}
for item in d:
if isinstance(d[item], dict):
n[item] = dict2obj(d[item])
elif isinstance(d[item], (list, tuple)):
n[item] = [dict2obj(elem) for elem in d[item]]
else:
n[item] = d[item]
return type('obj_from_dict', (object,), n)
else:
return d
>>> def dict2obj(d):
if isinstance(d, list):
d = [dict2obj(x) for x in d]
if not isinstance(d, dict):
return d
class C(object):
pass
o = C()
for k in d:
o.__dict__[k] = dict2obj(d[k])
return o
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
x .__ dict __. update (d)
должно работать нормально.
Это должно помочь вам начать:
class dict2obj(object):
def __init__(self, d):
self.__dict__['d'] = d
def __getattr__(self, key):
value = self.__dict__['d'][key]
if type(value) == type({}):
return dict2obj(value)
return value
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
x = dict2obj(d)
print x.a
print x.b.c
print x.d[1].foo
Это пока не работает для списков. Вам нужно будет обернуть списки в UserList и перегрузить __ getitem __
, чтобы обернуть dicts.
Позвольте мне объяснить решение, которое я почти использовал некоторое время назад. Но сначала причина, по которой я этого не сделал, проиллюстрирована тем фактом, что следующий код:
d = {'from': 1}
x = dict2obj(d)
print x.from
дает эту ошибку:
File "test.py", line 20
print x.from == 1
^
SyntaxError: invalid syntax
Поскольку "from" является ключевым словом Python, существуют определенные ключи словаря, которые вы не можете разрешить.
Теперь мой Решение позволяет получить доступ к элементам словаря, используя их имена напрямую. Но он также позволяет использовать «семантику словаря». Вот код с примером использования:
class dict2obj(dict):
def __init__(self, dict_):
super(dict2obj, self).__init__(dict_)
for key in self:
item = self[key]
if isinstance(item, list):
for idx, it in enumerate(item):
if isinstance(it, dict):
item[idx] = dict2obj(it)
elif isinstance(item, dict):
self[key] = dict2obj(item)
def __getattr__(self, key):
return self[key]
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
x = dict2obj(d)
assert x.a == x['a'] == 1
assert x.b.c == x['b']['c'] == 2
assert x.d[1].foo == x['d'][1]['foo'] == "bar"
x = type('new_dict', (object,), d)
затем добавьте к этому рекурсию, и все готово.
редактировать вот как я бы это реализовал:
>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
top = type('new', (object,), d)
seqs = tuple, list, set, frozenset
for i, j in d.items():
if isinstance(j, dict):
setattr(top, i, obj_dic(j))
elif isinstance(j, seqs):
setattr(top, i,
type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
else:
setattr(top, i, j)
return top
>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
class obj(object):
def __init__(self, d):
for a, b in d.items():
if isinstance(b, (list, tuple)):
setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
else:
setattr(self, a, obj(b) if isinstance(b, dict) else b)
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'
Основываясь на моем ответе на " python: Как динамически добавить свойство в класс? ":
class data(object):
def __init__(self,*args,**argd):
self.__dict__.update(dict(*args,**argd))
def makedata(d):
d2 = {}
for n in d:
d2[n] = trydata(d[n])
return data(d2)
def trydata(o):
if isinstance(o,dict):
return makedata(o)
elif isinstance(o,list):
return [trydata(i) for i in o]
else:
return o
Вы вызываете makedata
в словаре, который хотите преобразовать, или, возможно, trydata
в зависимости от то, что вы ожидаете в качестве ввода, и он выдает объект данных.
Примечания:
trydata
, если вам нужна дополнительная функциональность. xa = {}
или аналогичный. Обычно Вы хотите зеркально отразить dict иерархию в свой объект, но не список или кортежи, которые обычно являются на самом низком уровне. Таким образом, это - то, как я сделал это:
class defDictToObject(object):
def __init__(self, myDict):
for key, value in myDict.items():
if type(value) == dict:
setattr(self, key, defDictToObject(value))
else:
setattr(self, key, value)
, Таким образом, мы делаем:
myDict = { 'a': 1,
'b': {
'b1': {'x': 1,
'y': 2} },
'c': ['hi', 'bar']
}
и доберитесь:
x.b.b1.x
1
x.c
['привет', 'панель']